﻿Option Explicit On
Imports System.Xml

Public Class frmMain
    ' The main form behaves like a document that can be saved or opened.  Only a single
    ' configuration can be open at any time.
    Dim weightsArray(,) As Double
    Dim weightsNames() As String
    Dim gems() As Gem
    Dim items_head() As Item
    Dim items_shoulder() As Item
    Dim items_chest() As Item
    Dim items_hand() As Item
    Dim items_leg() As Item
    Dim items_neck() As Item
    Dim items_back() As Item
    Dim items_wrist() As Item
    Dim items_waist() As Item
    Dim items_foot() As Item
    Dim items_finger() As Item
    Dim items_trinket() As Item
    Dim items_twohand() As Item
    Dim items_onehand() As Item

    Dim prevVal As Double
    Dim filePath As String
    Dim fileName As String
    Dim saved As Boolean
    Private calcdone As Boolean
    Dim previousResultsExist As Boolean

    Dim WithEvents progressForm As frmProgress

    Const NUM_WEIGHTS = 23
    Dim WithEvents EditGemsForm As frmEditGems
    Dim WithEvents EditItemsForm As frmEditItems
    Dim WithEvents editWeightsForm As frmEditWeights
    Dim WithEvents myCalc As CalcManager
    Private bestSet As FullSet
    Dim noCandidatesFound As Boolean
    Dim noGemSetsFound As Boolean

    Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        ' Verify that unsaved stuff doesn't need saved.
        Dim msgresult As DialogResult

        ' If current is unsaved, prompt for save.  Save / Don't save, and then open a file.
        If saved = False Then
            If fileName = "" Then
                msgresult = MessageBox.Show("This document is unsaved.  Save before quitting?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            Else
                msgresult = MessageBox.Show("""" & fileName & """ is unsaved.  Save before quitting?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            End If
            ' If cancel, don't exit.  If yes, save and move on.
            ' if no, then just move on.
            If msgresult = Windows.Forms.DialogResult.Cancel Then
                e.Cancel = True
                Exit Sub
            End If
            If msgresult = Windows.Forms.DialogResult.Yes Then
                Dim tempe As System.EventArgs
                tempe = Nothing
                mnuSave_Click(Me, tempe)
                ' If user clicked cancel
                If saved = False Then
                    e.Cancel = True
                    Exit Sub
                End If
            End If
        End If
    End Sub

    Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        ' DEV VERSION
        MsgBox("This is a developer version and is intended only for testing. Please report any errors to Zerack @ Elitistjerks")

        ' Start a new file
        setupNewFile()

        ' no previous results
        previousResultsExist = False


        ' Set up the save and open dialogs.
        sveMain.Title = "DK Optimize - Save As..."
        sveMain.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
        sveMain.Filter = "All Files(*.*)|*.*|DK Optimize File(*.dko)|*.dko"
        sveMain.FilterIndex = 2
        sveMain.RestoreDirectory = True
        sveMain.DefaultExt = ".dko"
        sveMain.OverwritePrompt = True

        opnMain.Title = "DK Optimize - Open File"
        opnMain.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
        opnMain.Filter = "All Files(*.*)|*.*|DK Optimize File(*.dko)|*.dko"
        opnMain.FilterIndex = 2
        opnMain.RestoreDirectory = True
        opnMain.Multiselect = False
        opnMain.FileName = ""

        ' Make sure our constants file is here. Doing it separate since
        ' it doesn't get called / created by any of hte main form loading.
        ' has to be there if the user wants to calculate, though.
        If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml") = False Then
            Try
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_constants.xml", Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
            Catch
                MessageBox.Show("Error initializing data_constants.xml.  Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End
            End Try
        End If

        ' Make sure our internal procs file is here. Doing it separate since
        ' it doesn't get called / created by any of the main form loading.
        ' has to be there if the user wants to calculate, though.
        If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_internalprocs.xml") = False Then
            Try
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_internalprocs.xml", Windows.Forms.Application.CommonAppDataPath & "\data_internalprocs.xml")
            Catch
                MessageBox.Show("Error initializing data_internalprocs.xml.  Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End
            End Try
        End If

        ' Check the command line arguments.  If there is more than one
        ' argument we assume that the second argument is the file path
        ' that was double clicked to open the program.  Open that file.
        If UBound(Environment.GetCommandLineArgs) <> 0 Then
            ' Check to see if the file exists.
            If System.IO.File.Exists(Environment.GetCommandLineArgs(1)) = True Then
                Dim fileparts() As String
                Dim fileExt As String
                ReDim fileparts(0 To UBound(Split(Environment.GetCommandLineArgs(1), "\")))
                fileparts = Split(Environment.GetCommandLineArgs(1), "\")
                fileName = fileparts(UBound(fileparts))
                fileExt = Microsoft.VisualBasic.Right(fileName, 3)
                If fileExt <> "dko" Then
                    MessageBox.Show("Invalid program arguments. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End If
                filePath = Environment.GetCommandLineArgs(1)
                openFile(filePath)
            Else
                MessageBox.Show("Invalid program arguments.  DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End
            End If
        End If

    End Sub

    Private Sub Weights_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtStr.Enter, txtAP.Enter, txtCrit.Enter, txtHaste.Enter, txtArP.Enter, txtAgi.Enter, txtArmor.Enter, txtExp.Enter, txtMHSpeed.Enter, txtOHSpeed.Enter, txtMeleeHit.Enter, txtSpellHit.Enter, txtExtraHit.Enter, txtMHDPS.Enter, txtOHDPS.Enter, txtT7_2.Enter, txtT7_4.Enter, txtT8_2.Enter, txtT8_4.Enter, txtT9_2.Enter, txtT9_4.Enter, txtT10_2.Enter, txtT10_4.Enter
        ' Record the value of a text cell when we enter it, so that entering but not changing
        ' won't set off our custom stuff.
        prevVal = Double.Parse(DirectCast(sender, TextBox).Text)
    End Sub

    Private Sub Validate_Weights(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtStr.Validating, txtAP.Validating, txtCrit.Validating, txtHaste.Validating, txtArP.Validating, txtAgi.Validating, txtArmor.Validating, txtExp.Validating, txtMHSpeed.Validating, txtOHSpeed.Validating, txtMeleeHit.Validating, txtSpellHit.Validating, txtExtraHit.Validating, txtMHDPS.Validating, txtOHDPS.Validating, txtT7_2.Validating, txtT7_4.Validating, txtT8_2.Validating, txtT8_4.Validating, txtT9_2.Validating, txtT9_4.Validating, txtT10_2.Validating, txtT10_4.Validating

        ' Validate event for weights textboxes on the main form.
        ' If the value is negative, not a number, or greater than 100
        ' then refocus and select the text.  If the value is blank
        ' set the value of the text box to zero.

        If IsNumeric(DirectCast(sender, TextBox).Text) = True Then
            If Double.Parse(DirectCast(sender, TextBox).Text) < 0 Or Double.Parse(DirectCast(sender, TextBox).Text) > 10000 Then
                MessageBox.Show("Weights must be between 0 and 10000", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                DirectCast(sender, TextBox).Select(0, Len(DirectCast(sender, TextBox).Text))
                DirectCast(sender, TextBox).Focus()
                DirectCast(sender, TextBox).SelectAll()
                Exit Sub
            End If
        Else
            If DirectCast(sender, TextBox).Text = "" Then
                Dim tempDouble As Double = 0
                DirectCast(sender, TextBox).Text = tempDouble.ToString("##0.000")
            Else
                MessageBox.Show("Weights must be numeric.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                DirectCast(sender, TextBox).Select(0, Len(DirectCast(sender, TextBox).Text))
                DirectCast(sender, TextBox).Focus()
                DirectCast(sender, TextBox).SelectAll()
                Exit Sub
            End If
        End If

        ' Valid, so we reformat it appropriately.
        DirectCast(sender, TextBox).Text = Double.Parse(DirectCast(sender, TextBox).Text).ToString("###0.000")

        ' If the value changed from its previous value, set cboweights to custom.
        If Double.Parse(DirectCast(sender, TextBox).Text) <> prevVal Then
            cboWeights.SelectedIndex = 0
            ' No longer saved
            setSaved(False)
        End If

    End Sub

    Private Sub EnterWeightsText(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtStr.Enter, txtAP.Enter, txtCrit.Enter, txtHaste.Enter, txtArP.Enter, txtAgi.Enter, txtArmor.Enter, txtExp.Enter, txtMHSpeed.Enter, txtOHSpeed.Enter, txtMeleeHit.Enter, txtSpellHit.Enter, txtExtraHit.Enter, txtMHDPS.Enter, txtOHDPS.Enter, txtT7_2.Enter, txtT7_4.Enter, txtT8_2.Enter, txtT8_4.Enter, txtT9_2.Enter, txtT9_4.Enter, txtT10_2.Enter, txtT10_4.Enter
        ' Select text when we enter the box.
        DirectCast(sender, TextBox).SelectAll()
    End Sub

    Private Sub cboProf_Changed(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboProf_1.SelectedIndexChanged, cboProf_2.SelectedIndexChanged
        ' Handles making sure we don't have duplicate professions
        If DirectCast(sender, ComboBox).SelectedIndex <> 0 Then
            Select Case DirectCast(sender, ComboBox).Name
                Case "cboProf_1"
                    If DirectCast(sender, ComboBox).SelectedIndex = cboProf_2.SelectedIndex Then
                        MessageBox.Show("You cannot selected the same profession twice.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                        DirectCast(sender, ComboBox).SelectedIndex = 0
                    End If
                Case "cboProf_2"
                    If DirectCast(sender, ComboBox).SelectedIndex = cboProf_1.SelectedIndex Then
                        MessageBox.Show("You cannot selected the same profession twice.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                        DirectCast(sender, ComboBox).SelectedIndex = 0
                    End If
            End Select
        End If

        ' No longer saved
        setSaved(False)
    End Sub

    Private Sub cboForceTierChange(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboForce_T7.SelectedIndexChanged, cboForce_T8.SelectedIndexChanged, cboForce_T9.SelectedIndexChanged, cboForce_T10.SelectedIndexChanged
        ' Verify that we haven't forced more than 4 total set pieces.
        Dim totalSetPieces As Integer = 0

        If cboForce_T7.Text <> "" Then totalSetPieces += Integer.Parse(cboForce_T7.Text)
        If cboForce_T8.Text <> "" Then totalSetPieces += Integer.Parse(cboForce_T8.Text)
        If cboForce_T9.Text <> "" Then totalSetPieces += Integer.Parse(cboForce_T9.Text)
        If cboForce_T10.Text <> "" Then totalSetPieces += Integer.Parse(cboForce_T10.Text)

        If totalSetPieces > 4 Then
            MessageBox.Show("Cannot force more than 4 total Tier pieces.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            DirectCast(sender, ComboBox).SelectedIndex = 0
        End If

        ' No longer saved
        setSaved(False)

    End Sub

    Private Sub cboRace_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboRace.SelectedIndexChanged
        ' Enable or Disable the relevant Draenei Aura boxes depending on race selection.
        ' lastMaura remembers selection if / when the user changes to Draenei and back, since
        ' melee aura is forced for Draenei.
        Static lastMAura As Integer = -1

        Select Case cboRace.Text
            Case "Human", "Dwarf", "Night Elf", "Gnome"
                If lastMAura <> -1 Then
                    cboDAura_M.SelectedIndex = lastMAura
                End If
                lastMAura = -1
                cboDAura_M.Visible = True
                cboDAura_S.Visible = True
                cboDAura_M.Enabled = True
                lblDAura_M.Visible = True
                lblDAura_S.Visible = True
            Case "Draenei"
                lastMAura = cboDAura_M.SelectedIndex
                cboDAura_M.Visible = True
                cboDAura_M.SelectedIndex = 1
                cboDAura_M.Enabled = False
                cboDAura_S.Visible = True
                lblDAura_M.Visible = True
                lblDAura_S.Visible = True
            Case "Orc", "Undead", "Tauren", "Troll", "Blood Elf"
                If lastMAura <> -1 Then
                    cboDAura_M.SelectedIndex = lastMAura
                End If
                lastMAura = -1
                cboDAura_M.Visible = False
                cboDAura_S.Visible = False
                lblDAura_M.Visible = False
                lblDAura_S.Visible = False
        End Select

        ' No longer saved
        setSaved(False)
    End Sub

    Private Sub loadMasterWeights()
        ' Reads data.xml for weight sets and loads the names into a combo box
        ' and the values into arrays for use.
        Dim m_xmld As XmlDocument
        Dim m_nodelist As XmlNodeList
        Dim m_node As XmlNode
        Dim curIndex As Integer
        Dim loopvar As Integer

        If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml") = False Then
            Try
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_weights.xml", Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml")
            Catch
                MessageBox.Show("Error initializing data_weights.xml. Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
                End
            End Try
        End If

        Try
            m_xmld = New XmlDocument()
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml")
            m_nodelist = m_xmld.SelectNodes("/weightsets")
            m_node = m_nodelist(0)


            Dim msgResult As DialogResult
            Dim buildInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)
            If m_node.Attributes.GetNamedItem("version").Value <> buildInfo.ProductVersion Then
                ' If from an earlier version, prompt for replace.
                msgResult = MessageBox.Show("Weights appear to be from a different version of DK Optimize.  Would you like to reload the most current default values? Existing values will be lost.", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
                If msgResult = Windows.Forms.DialogResult.Yes Then
                    System.IO.File.Delete(Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml")
                    System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_weights.xml", Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml")
                End If
            End If

            m_xmld = New XmlDocument()
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_weights.xml")
            m_nodelist = m_xmld.SelectNodes("/weightsets/set")

            ReDim weightsArray(0 To m_nodelist.Count - 1, 0 To NUM_WEIGHTS - 1)
            ReDim weightsNames(0 To m_nodelist.Count - 1)
            curIndex = 0

            For Each m_node In m_nodelist
                weightsNames(curIndex) = m_node.Attributes.GetNamedItem("name").Value
                For loopvar = 0 To m_node.ChildNodes.Count - 1
                    weightsArray(curIndex, loopvar) = Double.Parse(m_node.ChildNodes.Item(loopvar).InnerText, System.Globalization.CultureInfo.InvariantCulture)
                Next
                curIndex += 1
            Next

            ' Weights are loaded, populate the list.
            cboWeights.Items.Clear()
            cboWeights.Items.Add("Custom Weights")
            For loopvar = 0 To UBound(weightsNames)
                cboWeights.Items.Add(weightsNames(loopvar))
            Next

            ' Check weights in the text fields against each loaded weight set since we don't want to set stuff to 
            ' custom if it isn't custom.  If it IS custom, set cboweights to "Custom" (index 0) otherwise set it to the matched
            ' index
            Dim foundMatchingWeights As Boolean = False

            For loopvar = 0 To UBound(weightsNames)
                If Double.Parse(txtStr.Text) = weightsArray(loopvar, 0) And _
                    Double.Parse(txtAP.Text) = weightsArray(loopvar, 1) And _
                    Double.Parse(txtCrit.Text) = weightsArray(loopvar, 2) And _
                    Double.Parse(txtHaste.Text) = weightsArray(loopvar, 3) And _
                    Double.Parse(txtArP.Text) = weightsArray(loopvar, 4) And _
                    Double.Parse(txtAgi.Text) = weightsArray(loopvar, 5) And _
                    Double.Parse(txtArmor.Text) = weightsArray(loopvar, 6) And _
                    Double.Parse(txtMeleeHit.Text) = weightsArray(loopvar, 7) And _
                    Double.Parse(txtSpellHit.Text) = weightsArray(loopvar, 8) And _
                    Double.Parse(txtExtraHit.Text) = weightsArray(loopvar, 9) And _
                    Double.Parse(txtExp.Text) = weightsArray(loopvar, 10) And _
                    Double.Parse(txtMHDPS.Text) = weightsArray(loopvar, 11) And _
                    Double.Parse(txtOHDPS.Text) = weightsArray(loopvar, 12) And _
                    Double.Parse(txtMHSpeed.Text) = weightsArray(loopvar, 13) And _
                    Double.Parse(txtOHSpeed.Text) = weightsArray(loopvar, 14) And _
                    Double.Parse(txtT7_2.Text) = weightsArray(loopvar, 15) And _
                    Double.Parse(txtT7_4.Text) = weightsArray(loopvar, 16) And _
                    Double.Parse(txtT8_2.Text) = weightsArray(loopvar, 17) And _
                    Double.Parse(txtT8_4.Text) = weightsArray(loopvar, 18) And _
                    Double.Parse(txtT9_2.Text) = weightsArray(loopvar, 19) And _
                    Double.Parse(txtT9_4.Text) = weightsArray(loopvar, 20) And _
                    Double.Parse(txtT10_2.Text) = weightsArray(loopvar, 21) And _
                    Double.Parse(txtT10_4.Text) = weightsArray(loopvar, 22) And _
                    foundMatchingWeights = False Then

                    cboWeights.SelectedIndex = loopvar + 1
                    foundMatchingWeights = True

                End If
            Next
            ' If no matching weights were found, then this is a custom set.  Set it as such.
            If foundMatchingWeights = False Then
                cboWeights.SelectedIndex = 0
            End If
        Catch
            MessageBox.Show("An unspecified error occurred while loading weights.  Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            End
        End Try

    End Sub

    Private Sub loadMasterItems()
        ' Read items from data.xml and load them into the grid on the form.
        ' Leave everything unchecked - this just loads 'potential' items.
        Dim m_xmld As XmlDocument
        Dim m_nodelist As XmlNodeList
        Dim m_node As XmlNode
        Dim curIndex As Integer

        Try

            If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_items.xml") = False Then
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_items.xml", Windows.Forms.Application.CommonAppDataPath & "\data_items.xml")
            End If

            m_xmld = New XmlDocument
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_items.xml")
            m_nodelist = m_xmld.SelectNodes("/items")
            m_node = m_nodelist(0)

            Dim msgResult As DialogResult
            Dim buildInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)
            If m_node.Attributes.GetNamedItem("version").Value <> buildInfo.ProductVersion Then
                ' If from an earlier version, prompt for replace.
                msgResult = MessageBox.Show("Items appear to be from a different version of DK Optimize.  Would you like to reload the most current default values? Existing values will be lost.", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
                If msgResult = Windows.Forms.DialogResult.Yes Then
                    System.IO.File.Delete(Windows.Forms.Application.CommonAppDataPath & "\data_items.xml")
                    System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_items.xml", Windows.Forms.Application.CommonAppDataPath & "\data_items.xml")
                End If
            End If


            m_xmld = New XmlDocument()
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_items.xml")

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/head/item")

            ReDim items_head(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_head(curIndex) = New Item
                items_head(curIndex).LoadFromNode(m_node, "head")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/shoulder/item")

            ReDim items_shoulder(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_shoulder(curIndex) = New Item
                items_shoulder(curIndex).LoadFromNode(m_node, "shoulder")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/chest/item")

            ReDim items_chest(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_chest(curIndex) = New Item
                items_chest(curIndex).LoadFromNode(m_node, "chest")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/hand/item")

            ReDim items_hand(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_hand(curIndex) = New Item
                items_hand(curIndex).LoadFromNode(m_node, "hand")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/leg/item")

            ReDim items_leg(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_leg(curIndex) = New Item
                items_leg(curIndex).LoadFromNode(m_node, "leg")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/neck/item")

            ReDim items_neck(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_neck(curIndex) = New Item
                items_neck(curIndex).LoadFromNode(m_node, "neck")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/back/item")

            ReDim items_back(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_back(curIndex) = New Item
                items_back(curIndex).LoadFromNode(m_node, "back")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/wrist/item")

            ReDim items_wrist(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_wrist(curIndex) = New Item
                items_wrist(curIndex).LoadFromNode(m_node, "wrist")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/waist/item")

            ReDim items_waist(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_waist(curIndex) = New Item
                items_waist(curIndex).LoadFromNode(m_node, "waist")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/foot/item")

            ReDim items_foot(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_foot(curIndex) = New Item
                items_foot(curIndex).LoadFromNode(m_node, "foot")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/finger/item")

            ReDim items_finger(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_finger(curIndex) = New Item
                items_finger(curIndex).LoadFromNode(m_node, "finger")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/trinket/item")

            ReDim items_trinket(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_trinket(curIndex) = New Item
                items_trinket(curIndex).LoadFromNode(m_node, "trinket")
                curIndex += 1
            Next

            ' Alright, one slot at a time. The first several are identical
            ' so lots of copied code here for readability.
            m_nodelist = m_xmld.SelectNodes("/items/twohand/item")

            ReDim items_twohand(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_twohand(curIndex) = New Item
                items_twohand(curIndex).LoadFromNode(m_node, "twohand")
                curIndex += 1
            Next

            m_nodelist = m_xmld.SelectNodes("/items/onehand/item")

            ReDim items_onehand(0 To m_nodelist.Count - 1)
            curIndex = 0
            For Each m_node In m_nodelist
                items_onehand(curIndex) = New Item
                items_onehand(curIndex).LoadFromNode(m_node, "onehand")
                curIndex += 1
            Next

            ' Okay, so items_* hold our items now.  Now we need to populate the various
            ' grd*** controls.  Remember that only the first column is enabled, but that's
            ' been done for us.
            Dim rowLoopvar As Integer

            With grdHead
                .AutoRedraw = False
                .Rows = UBound(items_head) + 2
                For rowLoopvar = 1 To UBound(items_head) + 1
                    items_head(rowLoopvar - 1).showStatic(grdHead, rowLoopvar, 2, "head", False)
                    grdHead.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdShoulder
                .AutoRedraw = False
                .Rows = UBound(items_shoulder) + 2
                For rowLoopvar = 1 To UBound(items_shoulder) + 1
                    items_shoulder(rowLoopvar - 1).showStatic(grdShoulder, rowLoopvar, 2, "shoulder", False)
                    grdShoulder.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdChest
                .AutoRedraw = False
                .Rows = UBound(items_chest) + 2
                For rowLoopvar = 1 To UBound(items_chest) + 1
                    items_chest(rowLoopvar - 1).showStatic(grdChest, rowLoopvar, 2, "chest", False)
                    grdChest.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdHand
                .AutoRedraw = False
                .Rows = UBound(items_hand) + 2
                For rowLoopvar = 1 To UBound(items_hand) + 1
                    items_hand(rowLoopvar - 1).showStatic(grdHand, rowLoopvar, 2, "hand", False)
                    grdHand.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdLeg
                .AutoRedraw = False
                .Rows = UBound(items_leg) + 2
                For rowLoopvar = 1 To UBound(items_leg) + 1
                    items_leg(rowLoopvar - 1).showStatic(grdLeg, rowLoopvar, 2, "leg", False)
                    grdLeg.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdNeck
                .AutoRedraw = False
                .Rows = UBound(items_neck) + 2
                For rowLoopvar = 1 To UBound(items_neck) + 1
                    items_neck(rowLoopvar - 1).showStatic(grdNeck, rowLoopvar, 2, "neck", False)
                    grdNeck.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdBack
                .AutoRedraw = False
                .Rows = UBound(items_back) + 2
                For rowLoopvar = 1 To UBound(items_back) + 1
                    items_back(rowLoopvar - 1).showStatic(grdBack, rowLoopvar, 2, "back", False)
                    grdBack.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdWrist
                .AutoRedraw = False
                .Rows = UBound(items_wrist) + 2
                For rowLoopvar = 1 To UBound(items_wrist) + 1
                    items_wrist(rowLoopvar - 1).showStatic(grdWrist, rowLoopvar, 2, "wrist", False)
                    grdWrist.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdWaist
                .AutoRedraw = False
                .Rows = UBound(items_waist) + 2
                For rowLoopvar = 1 To UBound(items_waist) + 1
                    items_waist(rowLoopvar - 1).showStatic(grdWaist, rowLoopvar, 2, "waist", False)
                    grdWaist.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdFoot
                .AutoRedraw = False
                .Rows = UBound(items_foot) + 2
                For rowLoopvar = 1 To UBound(items_foot) + 1
                    items_foot(rowLoopvar - 1).showStatic(grdFoot, rowLoopvar, 2, "foot", False)
                    grdFoot.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdFinger
                .AutoRedraw = False
                .Rows = UBound(items_finger) + 2
                For rowLoopvar = 1 To UBound(items_finger) + 1
                    items_finger(rowLoopvar - 1).showStatic(grdFinger, rowLoopvar, 2, "finger", False)
                    grdFinger.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grdTrinket
                .AutoRedraw = False
                .Rows = UBound(items_trinket) + 2
                For rowLoopvar = 1 To UBound(items_trinket) + 1
                    items_trinket(rowLoopvar - 1).showStatic(grdTrinket, rowLoopvar, 2, "trinket", False)
                    grdTrinket.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grd2HWeapon
                .AutoRedraw = False
                .Rows = UBound(items_twohand) + 2
                For rowLoopvar = 1 To UBound(items_twohand) + 1
                    items_twohand(rowLoopvar - 1).showStatic(grd2HWeapon, rowLoopvar, 2, "twohand", False)
                    grd2HWeapon.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

            With grd1HWeapon
                .AutoRedraw = False
                .Rows = UBound(items_onehand) + 2
                For rowLoopvar = 1 To UBound(items_onehand) + 1
                    items_onehand(rowLoopvar - 1).showStatic(grd1HWeapon, rowLoopvar, 2, "onehand", False)
                    grd1HWeapon.Cell(rowLoopvar, 1).Text = ""
                Next
                .Column(.Cols - 1).Sort(FlexCell.SortEnum.Descending)
                .AutoRedraw = True
                .Refresh()
            End With

        Catch
            MessageBox.Show("An unspecified error occurred while loading items.  Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            End
        End Try

    End Sub

    Private Sub loadMasterGems()
        ' Read gems from data.xml and load them into the grid on the form.
        ' leave everything unchecked - this just loads the 'potentials' as it were.
        ' and the values into arrays for use.
        Dim m_xmld As XmlDocument
        Dim m_nodelist As XmlNodeList
        Dim m_node As XmlNode
        Dim curIndex As Integer = 0

        Try

            If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml") = False Then
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_gems.xml", Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml")
            End If

            m_xmld = New XmlDocument()
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml")
            m_nodelist = m_xmld.SelectNodes("/gems")
            m_node = m_nodelist(0)

            Dim msgResult As DialogResult
            Dim buildInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)
            If m_node.Attributes.GetNamedItem("version").Value <> buildInfo.ProductVersion Then
                ' If from an earlier version, prompt for replace.
                msgResult = MessageBox.Show("Gems appear to be from a different version of DK Optimize.  Would you like to reload the most current default values?", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
                If msgResult = Windows.Forms.DialogResult.Yes Then
                    System.IO.File.Delete(Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml")
                    System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_gems.xml", Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml")
                End If
            End If

            m_xmld = New XmlDocument
            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml")
            m_nodelist = m_xmld.SelectNodes("/gems/gem")

            ReDim gems(0 To m_nodelist.Count - 1)

            For Each m_node In m_nodelist
                gems(curIndex) = New Gem
                gems(curIndex).LoadFromNode(m_node)
                curIndex += 1
            Next

            ' Gems have been loaded into gems.  Now populate grdGems with the values.
            Dim rowLoopvar As Integer

            ' Expand the grid to accomodate everything.
            grdGems.AutoRedraw = False
            grdGems.Rows = UBound(gems) + 2

            For rowLoopvar = 1 To UBound(gems) + 1
                gems(rowLoopvar - 1).showStatic(grdGems, rowLoopvar, 2)
                grdGems.Cell(rowLoopvar, 1).Text = ""
            Next

            grdGems.Column(3).Sort(FlexCell.SortEnum.Descending)

            grdGems.AutoRedraw = True
            grdGems.Refresh()

        Catch
            MessageBox.Show("An unspecified error occurred while loading gems. Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            End
        End Try

    End Sub

    Private Sub cboWeights_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboWeights.SelectedIndexChanged
        ' If we change to anything that isn't "Custom Weights" then 
        ' we load from weights_array.
        ' If we do change to custom weights, do nothing since it doesn't have any meaning
        ' in that context.
        If cboWeights.SelectedIndex <> 0 Then
            txtStr.Text = weightsArray(cboWeights.SelectedIndex - 1, 0).ToString("###0.000")
            txtAP.Text = weightsArray(cboWeights.SelectedIndex - 1, 1).ToString("###0.000")
            txtCrit.Text = weightsArray(cboWeights.SelectedIndex - 1, 2).ToString("###0.000")
            txtHaste.Text = weightsArray(cboWeights.SelectedIndex - 1, 3).ToString("###0.000")
            txtArP.Text = weightsArray(cboWeights.SelectedIndex - 1, 4).ToString("###0.000")
            txtAgi.Text = weightsArray(cboWeights.SelectedIndex - 1, 5).ToString("###0.000")
            txtArmor.Text = weightsArray(cboWeights.SelectedIndex - 1, 6).ToString("###0.000")
            txtMeleeHit.Text = weightsArray(cboWeights.SelectedIndex - 1, 7).ToString("###0.000")
            txtSpellHit.Text = weightsArray(cboWeights.SelectedIndex - 1, 8).ToString("###0.000")
            txtExtraHit.Text = weightsArray(cboWeights.SelectedIndex - 1, 9).ToString("###0.000")
            txtExp.Text = weightsArray(cboWeights.SelectedIndex - 1, 10).ToString("###0.000")
            txtMHDPS.Text = weightsArray(cboWeights.SelectedIndex - 1, 11).ToString("###0.000")
            txtOHDPS.Text = weightsArray(cboWeights.SelectedIndex - 1, 12).ToString("###0.000")
            txtMHSpeed.Text = weightsArray(cboWeights.SelectedIndex - 1, 13).ToString("###0.000")
            txtOHSpeed.Text = weightsArray(cboWeights.SelectedIndex - 1, 14).ToString("###0.000")
            txtT7_2.Text = weightsArray(cboWeights.SelectedIndex - 1, 15).ToString("###0.000")
            txtT7_4.Text = weightsArray(cboWeights.SelectedIndex - 1, 16).ToString("###0.000")
            txtT8_2.Text = weightsArray(cboWeights.SelectedIndex - 1, 17).ToString("###0.000")
            txtT8_4.Text = weightsArray(cboWeights.SelectedIndex - 1, 18).ToString("###0.000")
            txtT9_2.Text = weightsArray(cboWeights.SelectedIndex - 1, 19).ToString("###0.000")
            txtT9_4.Text = weightsArray(cboWeights.SelectedIndex - 1, 20).ToString("###0.000")
            txtT10_2.Text = weightsArray(cboWeights.SelectedIndex - 1, 21).ToString("###0.000")
            txtT10_4.Text = weightsArray(cboWeights.SelectedIndex - 1, 22).ToString("###0.000")
            ' Find the 'Primary Tree' if able.
            If InStr(cboWeights.Text, "Blood") <> 0 Then
                cboPrimaryTree.SelectedIndex = 1
            ElseIf InStr(cboWeights.Text, "Frost") <> 0 Then
                cboPrimaryTree.SelectedIndex = 2
            ElseIf InStr(cboWeights.Text, "Unholy") <> 0 Then
                cboPrimaryTree.SelectedIndex = 3
            Else
                cboPrimaryTree.SelectedIndex = 0
            End If

        End If

        ' No longer saved
        setSaved(False)

    End Sub

    Private Sub EditMasterGems(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuEditMasterGems.Click
        ' Spawn the master gem editing form as modal.
        ' We'll catch the unload event to do some work.
        Dim loopvar As Integer
        EditGemsForm = New frmEditGems
        EditGemsForm.EditGemSetup()
        For loopvar = 0 To UBound(gems)
            EditGemsForm.AddGem(gems(loopvar))
        Next
        EditGemsForm.DisplayGems()
        EditGemsForm.ShowDialog()
        EditGemsForm = Nothing
    End Sub

    Sub EditGemsComplete() Handles EditGemsForm.EditGemsComplete
        ' We have a little work do do here.  We're going to reload all the gems from data_gems.xml
        ' and then re-check the ones that need to be checked (i.e. were checked previously).
        Dim checkedGems() As String
        Dim notFoundList() As String
        Dim numChecked As Integer, numNotFound As Integer
        Dim loopvar As Integer, loopvar2 As Integer, loopvar3 As Integer

        ReDim checkedGems(0)
        ReDim notFoundList(0)

        numChecked = 0
        For loopvar = 0 To UBound(gems)
            For loopvar2 = 1 To grdGems.Rows - 1
                ' Note that "" is unchecked and "1" is checked.
                If grdGems.Cell(loopvar2, 2).Text = gems(loopvar).name And grdGems.Cell(loopvar2, 1).Text = "1" Then
                    numChecked += 1
                    ReDim Preserve checkedGems(0 To numChecked - 1)
                    checkedGems(numChecked - 1) = gems(loopvar).name
                End If
            Next
        Next

        ' We've stored our selections, now reload from the file.
        loadMasterGems()

        Dim foundGem As Boolean
        ' Fresh gems are loaded but nothing is selected. Iterate through and reselect gems with matching names.

        numNotFound = 0
        For loopvar = 0 To numChecked - 1
            foundGem = False
            For loopvar2 = 0 To UBound(gems)
                If checkedGems(loopvar) = gems(loopvar2).name Then
                    foundGem = True
                    For loopvar3 = 1 To grdGems.Rows - 1
                        If grdGems.Cell(loopvar3, 2).Text = gems(loopvar2).name Then
                            grdGems.Cell(loopvar3, 1).Text = "1"
                        End If
                    Next
                End If
            Next
            If foundGem = False Then
                numNotFound += 1
                ReDim Preserve notFoundList(0 To numNotFound - 1)
                notFoundList(UBound(notFoundList)) = checkedGems(loopvar)
            End If
        Next

        ' Alert the user to any gems that could not be found
        Dim missingGemString As String = ""
        If numNotFound <> 0 Then
            For loopvar = 0 To numNotFound - 1
                missingGemString &= """" & notFoundList(loopvar) & """"
                If loopvar <> numNotFound - 1 And numNotFound > 2 Then
                    missingGemString &= ","
                End If
                If loopvar = numNotFound - 2 And numNotFound > 1 Then
                    missingGemString &= " and"
                End If
                missingGemString &= " "
            Next
            If numNotFound > 1 Then
                missingGemString &= "are "
            Else
                missingGemString &= "is "
            End If
            MessageBox.Show("Due to changes in the Master Gem List, " & missingGemString & "no longer available.  Selection(s) have been lost.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
        End If


    End Sub

    Private Sub EditMasterItems(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuEditMasterItems.Click
        ' spawn the master item editing form modally.
        ' we'll catch the unload event to do some work.

        Dim loopvar As Integer
        EditItemsForm = New frmEditItems
        EditItemsForm.EditItemSetup()

        ' Since it's not an array, this is a little clunky, but not too terrible.
        ' Loop through adding each item from all 14 slots.
        For loopvar = 0 To UBound(items_head)
            EditItemsForm.AddItem(items_head(loopvar), "head")
        Next
        For loopvar = 0 To UBound(items_shoulder)
            EditItemsForm.AddItem(items_shoulder(loopvar), "shoulder")
        Next
        For loopvar = 0 To UBound(items_chest)
            EditItemsForm.AddItem(items_chest(loopvar), "chest")
        Next
        For loopvar = 0 To UBound(items_hand)
            EditItemsForm.AddItem(items_hand(loopvar), "hand")
        Next
        For loopvar = 0 To UBound(items_leg)
            EditItemsForm.AddItem(items_leg(loopvar), "leg")
        Next
        For loopvar = 0 To UBound(items_neck)
            EditItemsForm.AddItem(items_neck(loopvar), "neck")
        Next
        For loopvar = 0 To UBound(items_back)
            EditItemsForm.AddItem(items_back(loopvar), "back")
        Next
        For loopvar = 0 To UBound(items_wrist)
            EditItemsForm.AddItem(items_wrist(loopvar), "wrist")
        Next
        For loopvar = 0 To UBound(items_waist)
            EditItemsForm.AddItem(items_waist(loopvar), "waist")
        Next
        For loopvar = 0 To UBound(items_foot)
            EditItemsForm.AddItem(items_foot(loopvar), "foot")
        Next
        For loopvar = 0 To UBound(items_finger)
            EditItemsForm.AddItem(items_finger(loopvar), "finger")
        Next
        For loopvar = 0 To UBound(items_trinket)
            EditItemsForm.AddItem(items_trinket(loopvar), "trinket")
        Next
        For loopvar = 0 To UBound(items_onehand)
            EditItemsForm.AddItem(items_onehand(loopvar), "onehand")
        Next
        For loopvar = 0 To UBound(items_twohand)
            EditItemsForm.AddItem(items_twohand(loopvar), "twohand")
        Next

        ' All the items have been added, so display them and then show the form.
        EditItemsForm.DisplayItems()
        EditItemsForm.ShowDialog()
        EditItemsForm = Nothing
    End Sub

    Sub EditItemsComplete() Handles EditItemsForm.EditItemsComplete
        ' After a user edit of the items list,
        ' we have to do several things.  Record the names of all items that are selected,
        ' Next, reload the items from scratch with nothing selected.
        ' Next, re-check all the items that were previously selected that are still present, matching
        ' on name string.
        ' Finally, let the user know the names of any items that have been lost, since losing items
        ' makes us sad.

        Dim selectedStrings(,) As String
        Dim numStrings(0 To 13) As Integer
        Dim maxnumStrings As Integer
        Dim grdArray(0 To 13) As FlexCell.Grid
        Dim loopvar As Integer, loopvar2 As Integer

        grdArray(0) = grdHead
        grdArray(1) = grdShoulder
        grdArray(2) = grdChest
        grdArray(3) = grdHand
        grdArray(4) = grdLeg
        grdArray(5) = grdNeck
        grdArray(6) = grdBack
        grdArray(7) = grdWrist
        grdArray(8) = grdWaist
        grdArray(9) = grdFoot
        grdArray(10) = grdFinger
        grdArray(11) = grdTrinket
        grdArray(12) = grd2HWeapon
        grdArray(13) = grd1HWeapon

        maxnumStrings = 0
        ReDim selectedStrings(0 To 13, 0 To 0)

        ' Record selections
        For loopvar = 0 To 13
            numStrings(loopvar) = 0
            If grdArray(loopvar).Rows - 1 > 0 Then
                For loopvar2 = 1 To grdArray(loopvar).Rows - 1
                    If grdArray(loopvar).Cell(loopvar2, 1).Text = "1" Then 'if checked
                        numStrings(loopvar) += 1
                        If numStrings(loopvar) > maxnumStrings Then
                            maxnumStrings = numStrings(loopvar)
                            ReDim Preserve selectedStrings(0 To 13, 0 To numStrings(loopvar) - 1)
                        End If
                        selectedStrings(loopvar, numStrings(loopvar) - 1) = grdArray(loopvar).Cell(loopvar2, 2).Text
                    End If
                Next
            End If
        Next

        ' Reload items.
        loadMasterItems()

        ' Search through everything that was just loaded.  check stuff in selectedstrings.
        ' Note what can't be found.
        Dim notFound() As String
        Dim numNotFound As Integer
        Dim loopvar3 As Integer
        Dim found As Boolean

        numNotFound = 0
        ReDim notFound(0 To 0)
        For loopvar = 0 To 13
            For loopvar2 = 0 To numStrings(loopvar) - 1
                found = False
                For loopvar3 = 0 To grdArray(loopvar).Rows - 1
                    If selectedStrings(loopvar, loopvar2) = grdArray(loopvar).Cell(loopvar3, 2).Text Then
                        found = True
                        grdArray(loopvar).Cell(loopvar3, 1).Text = "1"
                    End If
                Next
                If found = False Then
                    numNotFound += 1
                    ReDim Preserve notFound(0 To numNotFound - 1)
                    notFound(numNotFound - 1) = selectedStrings(loopvar, loopvar2)
                End If
            Next
        Next

        ' Notfound() contains the strings that, well, haven't been found.
        ' Let the user know.
        Dim missingItemString As String = ""
        If numNotFound <> 0 Then
            For loopvar = 0 To numNotFound - 1
                missingItemString &= """" & notFound(loopvar) & """"
                If loopvar <> numNotFound - 1 And numNotFound > 2 Then
                    missingItemString &= ","
                End If
                If loopvar = numNotFound - 2 And numNotFound > 1 Then
                    missingItemString &= " and"
                End If
                missingItemString &= " "
            Next
            If numNotFound > 1 Then
                missingItemString &= "are "
            Else
                missingItemString &= "is "
            End If
            MessageBox.Show("Due to changes in the Master Item List, " & missingItemString & "no longer available.  Selection(s) have been lost.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
        End If

    End Sub

    Private Sub EditMasterWeights(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuEditMasterWeights.Click
        ' spawn the master item editing form modally.
        ' we'll catch the unload event to do some work.
        Dim loopvar As Integer
        Dim loopvar2 As Integer

        editWeightsForm = New frmEditWeights
        editWeightsForm.EditWeightsSetup(NUM_WEIGHTS)

        For loopvar = 0 To UBound(weightsNames)
            editWeightsForm.AddWeightSet(loopvar, weightsNames(loopvar))
            For loopvar2 = 0 To NUM_WEIGHTS - 1
                editWeightsForm.SetWeights(weightsNames(loopvar), loopvar2, weightsArray(loopvar, loopvar2))
            Next
            editWeightsForm.DisplayWeights()
        Next
        editWeightsForm.ShowDialog()
        editWeightsForm = Nothing
    End Sub

    Sub EditWeightsComplete() Handles editWeightsForm.EditWeightsComplete
        ' data_weights.xml has been populated with new weights.  What we're going
        ' to do now is re-populate the cboweights dropdown box and select the appropriate
        ' value.  Note that we are NOT going to alter values if the selected weight no longer
        ' exists - we will simply alert the user and change the box to 'custom'

        Dim prevName As String

        ' We can just reload using the existing procedure.
        prevName = cboWeights.Text

        Dim temp As Boolean

        ' loading weights doesn't actually change anything, but it can
        ' trigger the combo box change event.
        ' therefore just set saved to whatever it was before we loaded the weights.
        temp = saved
        loadMasterWeights()
        setSaved(temp)

        ' Now if the name has changed, notify the user.  Otherwise we are basically done.
        If cboWeights.Text <> prevName And prevName <> "Custom Weights" Then
            MessageBox.Show("The weight preset """ & prevName & """ no longer exists.  Current weights are now considered custom.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
        End If
    End Sub

    Private Sub cboDWor2H_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboDWor2H.SelectedIndexChanged
        ' Hide or Show the NoCS combo box depending on if we've selected
        ' two hand or dual wield as the mode.

        If cboDWor2H.SelectedIndex = 0 Then ' Two Hand
            lblNoCS.Visible = False
            cboNoCS.Visible = False
        Else
            cboNoCS.Visible = True
            lblNoCS.Visible = True
        End If

        setSaved(True)

    End Sub

    Private Sub setupNewFile()
        ' Set up the form for a new file.  Form caption, etc.

        filePath = ""
        fileName = ""

        Dim ctrl As Control
        Dim tempDouble As Double = 0
        For Each ctrl In grpWeights.Controls
            If TypeOf ctrl Is TextBox Then
                ctrl.Text = tempDouble.ToString("##0.000")
            End If
        Next

        ' Give cboweights a single entry of 'custom weights' and select it.
        cboWeights.Items.Clear()
        cboWeights.Items.Add("Custom Weights")
        cboWeights.SelectedIndex = 0

        ' Load the master weights list from data.xml
        loadMasterWeights()

        'Format the items region appropriately.  This includes setting up
        ' the dropdowns and checkboxes for the controls as well as sizing the header and
        ' columns.
        Dim ctrlFlex As Control
        Dim columnLoopvar As Integer

        For Each ctrl In tbsItems.Controls
            For Each ctrlFlex In ctrl.Controls
                If TypeOf ctrlFlex Is FlexCell.Grid Then
                    With DirectCast(ctrlFlex, FlexCell.Grid)
                        .AutoRedraw = False
                        .ExtendLastCol = True
                        .Rows = 2
                        .FixedRows = 1
                        .FrozenCols = 2
                        .Column(1).CellType = FlexCell.CellTypeEnum.CheckBox
                        .BoldFixedCell = False
                        .SelectionMode = FlexCell.SelectionModeEnum.ByCell
                        .AllowUserResizing = FlexCell.ResizeEnum.Columns
                        .AllowUserSort = True
                        Select Case .Name
                            Case "grdFinger"
                                .Cols = 20
                                .Column(0).Visible = False
                                .Cell(0, 1).Text = "Use"
                                .Column(1).Width = 40
                                .Cell(0, 2).Text = "Item Name"
                                .Column(2).Width = 200
                                .Cell(0, 3).Text = "Unique"
                                .Column(3).Width = 40
                                .Cell(0, 4).Text = "Str"
                                .Column(4).Width = 35
                                .Cell(0, 5).Text = "AP"
                                .Column(5).Width = 35
                                .Cell(0, 6).Text = "Crit"
                                .Column(6).Width = 35
                                .Cell(0, 7).Text = "Haste"
                                .Column(7).Width = 35
                                .Cell(0, 8).Text = "ArP"
                                .Column(8).Width = 35
                                .Cell(0, 9).Text = "Agi"
                                .Column(9).Width = 35
                                .Cell(0, 10).Text = "Exp"
                                .Column(10).Width = 35
                                .Cell(0, 11).Text = "Hit"
                                .Column(11).Width = 35
                                .Cell(0, 12).Text = "Armor"
                                .Column(12).Width = 35
                                .Cell(0, 13).Text = "Socket 1"
                                .Column(13).Width = 50
                                .Cell(0, 14).Text = "Socket 2"
                                .Column(14).Width = 50
                                .Cell(0, 15).Text = "Socket 3"
                                .Column(15).Width = 50
                                .Cell(0, 16).Text = "Socket"
                                .Column(16).Width = 40
                                .Cell(0, 17).Text = "Bonus"
                                .Column(17).Width = 40
                                .Cell(0, 18).Text = "Source"
                                .Column(18).Width = 130
                                .Cell(0, 19).Text = "iLvl"
                                .Column(19).Width = 30
                            Case "grdTrinket"
                                .Cols = 22
                                .Column(0).Visible = False
                                .Cell(0, 1).Text = "Use"
                                .Column(1).Width = 40
                                .Cell(0, 2).Text = "Item Name"
                                .Column(2).Width = 200
                                .Cell(0, 3).Text = "Proc"
                                .Column(3).Width = 36
                                .Cell(0, 4).Text = "Stat"
                                .Column(4).Width = 40
                                .Cell(0, 5).Text = "Uptime"
                                .Column(5).Width = 40
                                .Cell(0, 6).Text = "Str"
                                .Column(6).Width = 35
                                .Cell(0, 7).Text = "AP"
                                .Column(7).Width = 35
                                .Cell(0, 8).Text = "Crit"
                                .Column(8).Width = 35
                                .Cell(0, 9).Text = "Haste"
                                .Column(9).Width = 35
                                .Cell(0, 10).Text = "ArP"
                                .Column(10).Width = 35
                                .Cell(0, 11).Text = "Agi"
                                .Column(11).Width = 35
                                .Cell(0, 12).Text = "Exp"
                                .Column(12).Width = 35
                                .Cell(0, 13).Text = "Hit"
                                .Column(13).Width = 35
                                .Cell(0, 14).Text = "Armor"
                                .Column(14).Width = 35
                                .Cell(0, 15).Text = "Socket 1"
                                .Column(15).Width = 50
                                .Cell(0, 16).Text = "Socket 2"
                                .Column(16).Width = 50
                                .Cell(0, 17).Text = "Socket 3"
                                .Column(17).Width = 50
                                .Cell(0, 18).Text = "Socket"
                                .Column(18).Width = 40
                                .Cell(0, 19).Text = "Bonus"
                                .Column(19).Width = 40
                                .Cell(0, 20).Text = "Source"
                                .Column(20).Width = 130
                                .Cell(0, 21).Text = "iLvl"
                                .Column(21).Width = 30
                            Case "grd2HWeapon"
                                .Cols = 22
                                .Column(0).Visible = False
                                .Cell(0, 1).Text = "Use"
                                .Column(1).Width = 40
                                .Cell(0, 2).Text = "Item Name"
                                .Column(2).Width = 200
                                .Cell(0, 3).Text = "Type"
                                .Column(3).Width = 50
                                .Cell(0, 4).Text = "DPS"
                                .Column(4).Width = 40
                                .Cell(0, 5).Text = "Speed"
                                .Column(5).Width = 40
                                .Cell(0, 6).Text = "Str"
                                .Column(6).Width = 35
                                .Cell(0, 7).Text = "AP"
                                .Column(7).Width = 35
                                .Cell(0, 8).Text = "Crit"
                                .Column(8).Width = 35
                                .Cell(0, 9).Text = "Haste"
                                .Column(9).Width = 35
                                .Cell(0, 10).Text = "ArP"
                                .Column(10).Width = 35
                                .Cell(0, 11).Text = "Agi"
                                .Column(11).Width = 35
                                .Cell(0, 12).Text = "Exp"
                                .Column(12).Width = 35
                                .Cell(0, 13).Text = "Hit"
                                .Column(13).Width = 35
                                .Cell(0, 14).Text = "Armor"
                                .Column(14).Width = 35
                                .Cell(0, 15).Text = "Socket 1"
                                .Column(15).Width = 50
                                .Cell(0, 16).Text = "Socket 2"
                                .Column(16).Width = 50
                                .Cell(0, 17).Text = "Socket 3"
                                .Column(17).Width = 50
                                .Cell(0, 18).Text = "Socket"
                                .Column(18).Width = 40
                                .Cell(0, 19).Text = "Bonus"
                                .Column(19).Width = 40
                                .Cell(0, 20).Text = "Source"
                                .Column(20).Width = 130
                                .Cell(0, 21).Text = "iLvl"
                                .Column(21).Width = 30
                            Case "grd1HWeapon"
                                .Cols = 24
                                .Column(0).Visible = False
                                .Cell(0, 1).Text = "Use"
                                .Column(1).Width = 40
                                .Cell(0, 2).Text = "Item Name"
                                .Column(2).Width = 200
                                .Cell(0, 3).Text = "Type"
                                .Column(3).Width = 50
                                .Cell(0, 4).Text = "Unique"
                                .Column(4).Width = 40
                                .Cell(0, 5).Text = "Hand"
                                .Column(5).Width = 60
                                .Cell(0, 6).Text = "DPS"
                                .Column(6).Width = 40
                                .Cell(0, 7).Text = "Speed"
                                .Column(7).Width = 40
                                .Cell(0, 8).Text = "Str"
                                .Column(8).Width = 35
                                .Cell(0, 9).Text = "AP"
                                .Column(9).Width = 35
                                .Cell(0, 10).Text = "Crit"
                                .Column(10).Width = 35
                                .Cell(0, 11).Text = "Haste"
                                .Column(11).Width = 35
                                .Cell(0, 12).Text = "ArP"
                                .Column(12).Width = 35
                                .Cell(0, 13).Text = "Agi"
                                .Column(13).Width = 35
                                .Cell(0, 14).Text = "Exp"
                                .Column(14).Width = 35
                                .Cell(0, 15).Text = "Hit"
                                .Column(15).Width = 35
                                .Cell(0, 16).Text = "Armor"
                                .Column(16).Width = 35
                                .Cell(0, 17).Text = "Socket 1"
                                .Column(17).Width = 50
                                .Cell(0, 18).Text = "Socket 2"
                                .Column(18).Width = 50
                                .Cell(0, 19).Text = "Socket 3"
                                .Column(19).Width = 50
                                .Cell(0, 20).Text = "Socket"
                                .Column(20).Width = 40
                                .Cell(0, 21).Text = "Bonus"
                                .Column(21).Width = 40
                                .Cell(0, 22).Text = "Source"
                                .Column(22).Width = 130
                                .Cell(0, 23).Text = "iLvl"
                                .Column(23).Width = 30
                            Case Else
                                .Cols = 19
                                .Column(0).Visible = False
                                .Cell(0, 1).Text = "Use"
                                .Column(1).Width = 40
                                .Cell(0, 2).Text = "Item Name"
                                .Column(2).Width = 200
                                .Cell(0, 3).Text = "Str"
                                .Column(3).Width = 35
                                .Cell(0, 4).Text = "AP"
                                .Column(4).Width = 35
                                .Cell(0, 5).Text = "Crit"
                                .Column(5).Width = 35
                                .Cell(0, 6).Text = "Haste"
                                .Column(6).Width = 35
                                .Cell(0, 7).Text = "ArP"
                                .Column(7).Width = 35
                                .Cell(0, 8).Text = "Agi"
                                .Column(8).Width = 35
                                .Cell(0, 9).Text = "Exp"
                                .Column(9).Width = 35
                                .Cell(0, 10).Text = "Hit"
                                .Column(10).Width = 35
                                .Cell(0, 11).Text = "Armor"
                                .Column(11).Width = 35
                                .Cell(0, 12).Text = "Socket 1"
                                .Column(12).Width = 50
                                .Cell(0, 13).Text = "Socket 2"
                                .Column(13).Width = 50
                                .Cell(0, 14).Text = "Socket 3"
                                .Column(14).Width = 50
                                .Cell(0, 15).Text = "Socket"
                                .Column(15).Width = 40
                                .Cell(0, 16).Text = "Bonus"
                                .Column(16).Width = 40
                                .Cell(0, 17).Text = "Source"
                                .Column(17).Width = 130
                                .Cell(0, 18).Text = "iLvl"
                                .Column(18).Width = 30
                        End Select

                        For columnLoopvar = 2 To .Cols - 1
                            .Column(columnLoopvar).Locked = True
                        Next

                        .AutoRedraw = True
                        .Refresh()
                    End With
                End If
            Next
        Next

        ' Load items
        loadMasterItems()

        ' Format the Gems region appropriately.  This includes setting up
        ' the dropdowns and checkboxes for the control as well as
        ' Sizing and Header columns.

        grdGems.AutoRedraw = False
        grdGems.Cols = 14
        grdGems.Rows = 2
        grdGems.ExtendLastCol = True
        grdGems.Column(0).Visible = False
        grdGems.Column(1).CellType = FlexCell.CellTypeEnum.CheckBox
        grdGems.BoldFixedCell = False
        grdGems.FrozenCols = 1

        ' Set the column headers
        grdGems.Cell(0, 1).Text = "Use"
        grdGems.Cell(0, 2).Text = "Gem Name"
        grdGems.Cell(0, 3).Text = "Color"
        grdGems.Cell(0, 4).Text = "Str"
        grdGems.Cell(0, 5).Text = "AP"
        grdGems.Cell(0, 6).Text = "Crit"
        grdGems.Cell(0, 7).Text = "Haste"
        grdGems.Cell(0, 8).Text = "ArP"
        grdGems.Cell(0, 9).Text = "Agi"
        grdGems.Cell(0, 10).Text = "Exp"
        grdGems.Cell(0, 11).Text = "Hit"
        grdGems.Cell(0, 12).Text = "JC Gem"
        grdGems.Column(12).Visible = False
        grdGems.Cell(0, 13).Text = "Unique"

        ' Set the column widths
        Dim loopvar As Integer
        For loopvar = 1 To grdGems.Cols - 1
            grdGems.Column(loopvar).Width = 40
        Next

        ' Lock the columns except for the checkbox.
        For loopvar = 2 To grdGems.Cols - 1
            grdGems.Column(loopvar).Locked = True
        Next

        grdGems.Column(1).Width = 40
        grdGems.Column(2).Width = 170
        grdGems.Column(3).Width = 75
        grdGems.Column(12).Width = 50

        ' Load the gems
        loadMasterGems()

        grdGems.AutoRedraw = True
        grdGems.Refresh()

        ' Select Enchants Checkboxes
        For Each ctrl In grpEnchants.Controls
            If TypeOf ctrl Is CheckBox Then
                DirectCast(ctrl, CheckBox).Checked = True
            End If
        Next

        ' Populate the character dropdowns.  Again fairly annoying, but meh.
        cboRace.Items.Clear()
        cboRace.Items.Add("Human")
        cboRace.Items.Add("Dwarf")
        cboRace.Items.Add("Night Elf")
        cboRace.Items.Add("Gnome")
        cboRace.Items.Add("Draenei")
        cboRace.Items.Add("Orc")
        cboRace.Items.Add("Undead")
        cboRace.Items.Add("Tauren")
        cboRace.Items.Add("Troll")
        cboRace.Items.Add("Blood Elf")
        cboRace.SelectedIndex = 0

        cboForce_T7.Items.Clear()
        cboForce_T7.Items.Add("0")
        cboForce_T7.Items.Add("2")
        cboForce_T7.Items.Add("4")
        cboForce_T7.SelectedIndex = 0

        cboForce_T8.Items.Clear()
        cboForce_T8.Items.Add("0")
        cboForce_T8.Items.Add("2")
        cboForce_T8.Items.Add("4")
        cboForce_T8.SelectedIndex = 0

        cboForce_T9.Items.Clear()
        cboForce_T9.Items.Add("0")
        cboForce_T9.Items.Add("2")
        cboForce_T9.Items.Add("4")
        cboForce_T9.SelectedIndex = 0

        cboForce_T10.Items.Clear()
        cboForce_T10.Items.Add("0")
        cboForce_T10.Items.Add("2")
        cboForce_T10.Items.Add("4")
        cboForce_T10.SelectedIndex = 0

        cboProf_1.Items.Clear()
        cboProf_1.Items.Add("None")
        cboProf_1.Items.Add("Alchemy")
        cboProf_1.Items.Add("Blacksmithing")
        cboProf_1.Items.Add("Jewelcrafting")
        cboProf_1.Items.Add("Enchanting")
        cboProf_1.Items.Add("Engineering")
        cboProf_1.Items.Add("Inscription")
        cboProf_1.Items.Add("Leatherworking")
        cboProf_1.Items.Add("Skinning")
        cboProf_1.Items.Add("Tailoring")
        cboProf_1.SelectedIndex = 0

        cboProf_2.Items.Clear()
        cboProf_2.Items.Add("None")
        cboProf_2.Items.Add("Alchemy")
        cboProf_2.Items.Add("Blacksmithing")
        cboProf_2.Items.Add("Jewelcrafting")
        cboProf_2.Items.Add("Enchanting")
        cboProf_2.Items.Add("Engineering")
        cboProf_2.Items.Add("Inscription")
        cboProf_2.Items.Add("Leatherworking")
        cboProf_2.Items.Add("Skinning")
        cboProf_2.Items.Add("Tailoring")
        cboProf_2.SelectedIndex = 0

        cboDWor2H.Items.Clear()
        cboDWor2H.Items.Add("Two Handed")
        cboDWor2H.Items.Add("Dual Wield")
        cboDWor2H.SelectedIndex = 0

        cboNoCS.Items.Clear()
        cboNoCS.Items.Add("0%")
        cboNoCS.Items.Add("1%")
        cboNoCS.Items.Add("2%")
        cboNoCS.Items.Add("3%")
        cboNoCS.SelectedIndex = 0
        cboNoCS.Visible = False ' Set invisible to start since 2H is selected.
        lblNoCS.Visible = False

        cboDAura_M.Items.Clear()
        cboDAura_M.Items.Add("No")
        cboDAura_M.Items.Add("Yes")
        cboDAura_M.SelectedIndex = 0

        cboDAura_S.Items.Clear()
        cboDAura_S.Items.Add("No")
        cboDAura_S.Items.Add("Yes")
        cboDAura_S.SelectedIndex = 0

        cboSpellTalents.Items.Clear()
        cboSpellTalents.Items.Add("0%")
        cboSpellTalents.Items.Add("1%")
        cboSpellTalents.Items.Add("2%")
        cboSpellTalents.Items.Add("3%")
        cboSpellTalents.SelectedIndex = 0

        cboExpTalents.Items.Clear()
        cboExpTalents.Items.Add("0")
        cboExpTalents.Items.Add("1")
        cboExpTalents.Items.Add("2")
        cboExpTalents.Items.Add("3")
        cboExpTalents.Items.Add("4")
        cboExpTalents.Items.Add("5")
        cboExpTalents.Items.Add("6")
        cboExpTalents.Items.Add("7")
        cboExpTalents.Items.Add("8")
        cboExpTalents.Items.Add("9")
        cboExpTalents.SelectedIndex = 0

        cboArPTalents.Items.Clear()
        cboArPTalents.Items.Add("0%")
        cboArPTalents.Items.Add("2%")
        cboArPTalents.Items.Add("4%")
        cboArPTalents.Items.Add("6%")
        cboArPTalents.Items.Add("8%")
        cboArPTalents.Items.Add("10%")
        cboArPTalents.SelectedIndex = 0

        cboForceHitCap.Items.Clear()
        cboForceHitCap.Items.Add("None")
        cboForceHitCap.Items.Add("Melee")
        cboForceHitCap.Items.Add("Spell")
        cboForceHitCap.SelectedIndex = 0

        cboForceExpertiseCap.Items.Clear()
        cboForceExpertiseCap.Items.Add("No")
        cboForceExpertiseCap.Items.Add("Yes")
        cboForceExpertiseCap.SelectedIndex = 0

        cboPrimaryTree.Items.Clear()
        cboPrimaryTree.Items.Add("None")
        cboPrimaryTree.Items.Add("Blood")
        cboPrimaryTree.Items.Add("Frost")
        cboPrimaryTree.Items.Add("Unholy")
        cboPrimaryTree.SelectedIndex = 0

        setSaved(True)
    End Sub

    Private Sub setSaved(ByVal val As Boolean)
        saved = val
        If fileName <> "" Then
            ' Set the caption equal to the filename and the correct saved
            ' state indicator as *
            Me.Text = "DK Optimize - " & fileName
            If saved = False Then
                Me.Text = Me.Text & "*"
            End If
        Else
            ' If there is no file name, then it's a new document and
            ' we call it as such.
            Me.Text = "DK Optimize - New Document"
        End If
    End Sub

    Private Sub mnuNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuNew.Click

        Dim msgresult As DialogResult

        ' If current is unsaved, prompt for save.  Save / Don't save, and then open a new file.
        If saved = False Then
            If fileName = "" Then
                msgresult = MessageBox.Show("This document is unsaved.  Save before continuing?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            Else
                msgresult = MessageBox.Show("""" & fileName & """ is unsaved.  Save before continuing?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            End If
            ' If cancel, exit.  If yes, save and move on.
            ' if no, then just move on.
            If msgresult = Windows.Forms.DialogResult.Cancel Then Exit Sub
            If msgresult = Windows.Forms.DialogResult.Yes Then
                Dim tempe As System.EventArgs
                tempe = Nothing
                mnuSave_Click(Me, tempe)
            End If
        End If

        setupNewFile()

    End Sub

    Private Sub saveFile(ByVal fullPath As String)
        ' Do the actual work of saving.  Takes a filename
        ' from save or saveas.

        ' The document will be saved in XML format. Shouldn't be terrible overall.
        ' but will sort of be a pain in the ass to write since it's repetitive but
        ' not loopable really
        Dim loopvar As Integer, loopvar2 As Integer
        Dim xmlWriter As New XmlTextWriter(fullPath, System.Text.Encoding.UTF8)
        Dim grdArray(0 To 13) As FlexCell.Grid
        Dim slotArray(0 To 13) As String

        slotArray(0) = "head"
        slotArray(1) = "shoulder"
        slotArray(2) = "chest"
        slotArray(3) = "hand"
        slotArray(4) = "leg"
        slotArray(5) = "neck"
        slotArray(6) = "back"
        slotArray(7) = "wrist"
        slotArray(8) = "waist"
        slotArray(9) = "foot"
        slotArray(10) = "finger"
        slotArray(11) = "trinket"
        slotArray(12) = "twohand"
        slotArray(13) = "onehand"

        grdArray(0) = grdHead
        grdArray(1) = grdShoulder
        grdArray(2) = grdChest
        grdArray(3) = grdHand
        grdArray(4) = grdLeg
        grdArray(5) = grdNeck
        grdArray(6) = grdBack
        grdArray(7) = grdWrist
        grdArray(8) = grdWaist
        grdArray(9) = grdFoot
        grdArray(10) = grdFinger
        grdArray(11) = grdTrinket
        grdArray(12) = grd2HWeapon
        grdArray(13) = grd1HWeapon

        xmlWriter.WriteStartDocument()
        xmlWriter.WriteWhitespace(vbNewLine)
        xmlWriter.WriteStartElement("config")

        ' Weights first
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteStartElement("weights")
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("str", Double.Parse(txtStr.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("ap", Double.Parse(txtAP.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("crit", Double.Parse(txtCrit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("haste", Double.Parse(txtHaste.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("arp", Double.Parse(txtArP.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("agi", Double.Parse(txtAgi.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("armor", Double.Parse(txtArmor.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("hit", Double.Parse(txtMeleeHit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("sphit", Double.Parse(txtSpellHit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("exhit", Double.Parse(txtExtraHit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("exp", Double.Parse(txtExp.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("mhdps", Double.Parse(txtMHDPS.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("ohdps", Double.Parse(txtOHDPS.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("mhspeed", Double.Parse(txtMHSpeed.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("ohspeed", Double.Parse(txtOHSpeed.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t7_2", Double.Parse(txtT7_2.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t7_4", Double.Parse(txtT7_4.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t8_2", Double.Parse(txtT8_2.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t8_4", Double.Parse(txtT8_4.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t9_2", Double.Parse(txtT9_2.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t9_4", Double.Parse(txtT9_4.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t10_2", Double.Parse(txtT10_2.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("t10_4", Double.Parse(txtT10_4.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteEndElement()

        ' Items now.  Loop through each and write it.  We'll write slot indexes to make this easy.
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteStartElement("items")
        For loopvar2 = 0 To 13
            xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
            xmlWriter.WriteStartElement(slotArray(loopvar2))
            For loopvar = 1 To grdArray(loopvar2).Rows - 1
                If grdArray(loopvar2).Cell(loopvar, 1).Text = "1" Then
                    ' Selected, write it.
                    xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab & vbTab)
                    xmlWriter.WriteStartElement("item")
                    xmlWriter.WriteAttributeString("name", grdArray(loopvar2).Cell(loopvar, 2).Text)
                    xmlWriter.WriteEndElement()
                End If
            Next
            xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
            xmlWriter.WriteEndElement()
        Next
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteEndElement()

        ' Gems now.  Loop through the grid and write 'em out.
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteStartElement("gems")
        For loopvar = 1 To grdGems.Rows - 1
            If grdGems.Cell(loopvar, 1).Text = "1" Then
                xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
                xmlWriter.WriteStartElement("gem")
                xmlWriter.WriteAttributeString("name", grdGems.Cell(loopvar, 2).Text)
                xmlWriter.WriteEndElement()
            End If
        Next
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteEndElement()

        ' Enchants
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteStartElement("enchants")
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("boots_icewalker", chkEBoots_Icewalker.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("boots_greaterassault", chkEBoots_Assault.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("gloves_crusher", chkEGloves_Crusher.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("gloves_majorstrength", chkEGloves_Strength.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("gloves_precision", chkEGloves_Precision.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("bracers_greaterassault", chkEBracers_Assault.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("bracers_expertise", chkEBracers_Exp.Checked)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteEndElement()

        ' Misc checkboxes and options now.
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)
        xmlWriter.WriteStartElement("misc")
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("race", cboRace.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_t7", cboForce_T7.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_t8", cboForce_T8.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_t9", cboForce_T9.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_t10", cboForce_T10.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("prof1", cboProf_1.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("prof2", cboProf_2.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("dwor2h", cboDWor2H.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("spellhittalents", cboSpellTalents.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("exptalents", cboExpTalents.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("arptalents", cboArPTalents.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("nocs", cboNoCS.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("daura_melee", cboDAura_M.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("daura_spell", cboDAura_S.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_hitcap", cboForceHitCap.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("force_expcap", cboForceExpertiseCap.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab & vbTab)
        xmlWriter.WriteElementString("primarytree", cboPrimaryTree.SelectedIndex)
        xmlWriter.WriteWhitespace(vbNewLine & vbTab)

        xmlWriter.WriteEndElement()

        ' Closing Information.
        xmlWriter.WriteWhitespace(vbNewLine)
        xmlWriter.WriteEndElement()
        xmlWriter.WriteEndDocument()
        xmlWriter.Close()

        ' Saved, yay.
        setSaved(True)

    End Sub

    Private Sub openFile(ByVal fullPath As String)
        ' Does the actual work of opening.  We will definitely have a filename when
        ' this is called.
        '
        ' fullpath needs to have the filename in it also, i.e. c:\dkoptimize\myconfig.dko

        Dim m_xmld As XmlDocument
        Dim m_nodelist As XmlNodeList
        Dim m_node As XmlNode

        Dim unfound_items() As String
        Dim num_unfound_items As Integer

        Dim unfound_gems() As String
        Dim num_unfound_gems As Integer

        Dim selectedString As String
        Dim slotArray(0 To 13) As String
        Dim grdArray(0 To 13) As FlexCell.Grid

        grdArray(0) = grdHead
        grdArray(1) = grdShoulder
        grdArray(2) = grdChest
        grdArray(3) = grdHand
        grdArray(4) = grdLeg
        grdArray(5) = grdNeck
        grdArray(6) = grdBack
        grdArray(7) = grdWrist
        grdArray(8) = grdWaist
        grdArray(9) = grdFoot
        grdArray(10) = grdFinger
        grdArray(11) = grdTrinket
        grdArray(12) = grd2HWeapon
        grdArray(13) = grd1HWeapon

        slotArray(0) = "head"
        slotArray(1) = "shoulder"
        slotArray(2) = "chest"
        slotArray(3) = "hand"
        slotArray(4) = "leg"
        slotArray(5) = "neck"
        slotArray(6) = "back"
        slotArray(7) = "wrist"
        slotArray(8) = "waist"
        slotArray(9) = "foot"
        slotArray(10) = "finger"
        slotArray(11) = "trinket"
        slotArray(12) = "twohand"
        slotArray(13) = "onehand"

        m_xmld = New XmlDocument()
        m_xmld.Load(fullPath)

        ' Weights first
        m_nodelist = m_xmld.SelectNodes("/config/weights")
        m_node = m_nodelist(0)
        txtStr.Text = Double.Parse(m_node.ChildNodes.Item(0).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtAP.Text = Double.Parse(m_node.ChildNodes.Item(1).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtCrit.Text = Double.Parse(m_node.ChildNodes.Item(2).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtHaste.Text = Double.Parse(m_node.ChildNodes.Item(3).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtArP.Text = Double.Parse(m_node.ChildNodes.Item(4).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtAgi.Text = Double.Parse(m_node.ChildNodes.Item(5).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtArmor.Text = Double.Parse(m_node.ChildNodes.Item(6).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtMeleeHit.Text = Double.Parse(m_node.ChildNodes.Item(7).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtSpellHit.Text = Double.Parse(m_node.ChildNodes.Item(8).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtExtraHit.Text = Double.Parse(m_node.ChildNodes.Item(9).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtExp.Text = Double.Parse(m_node.ChildNodes.Item(10).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtMHDPS.Text = Double.Parse(m_node.ChildNodes.Item(11).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtOHDPS.Text = Double.Parse(m_node.ChildNodes.Item(12).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtMHSpeed.Text = Double.Parse(m_node.ChildNodes.Item(13).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtOHSpeed.Text = Double.Parse(m_node.ChildNodes.Item(14).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT7_2.Text = Double.Parse(m_node.ChildNodes.Item(15).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT7_4.Text = Double.Parse(m_node.ChildNodes.Item(16).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT8_2.Text = Double.Parse(m_node.ChildNodes.Item(17).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT8_4.Text = Double.Parse(m_node.ChildNodes.Item(18).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT9_2.Text = Double.Parse(m_node.ChildNodes.Item(19).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        txtT9_4.Text = Double.Parse(m_node.ChildNodes.Item(20).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        Try
            txtT10_2.Text = Double.Parse(m_node.ChildNodes.Item(21).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
            txtT10_4.Text = Double.Parse(m_node.ChildNodes.Item(22).InnerText, System.Globalization.CultureInfo.InvariantCulture).ToString("##0.000")
        Catch ex As Exception
            ' If there was an error here, it's an older file.
            txtT10_2.Text = "0.000"
            txtT10_4.Text = "0.000"
        End Try

        ' Items.
        ' Loop through 0 to 13 and load / write for each '
        Dim loopvar As Integer, loopvar2 As Integer
        Dim found As Boolean
        num_unfound_items = 0
        ReDim unfound_items(0 To 0)
        For loopvar = 0 To 13
            m_nodelist = m_xmld.SelectNodes("/config/items/" & slotArray(loopvar) & "/item")
            For Each m_node In m_nodelist
                ' Check the boxes!
                selectedString = m_node.Attributes.GetNamedItem("name").Value
                found = False
                For loopvar2 = 1 To grdArray(loopvar).Rows - 1
                    If grdArray(loopvar).Cell(loopvar2, 2).Text = selectedString Then
                        found = True
                        grdArray(loopvar).Cell(loopvar2, 1).Text = "1"
                    End If
                Next
                If found = False Then
                    num_unfound_items += 1
                    ReDim Preserve unfound_items(0 To num_unfound_items - 1)
                    unfound_items(num_unfound_items - 1) = selectedString
                End If
            Next
        Next

        ' Gems.  Check all the gem names and keep track of the unfound ones.
        m_nodelist = m_xmld.SelectNodes("/config/gems/gem")
        num_unfound_gems = 0
        ReDim unfound_gems(0 To 0)
        For Each m_node In m_nodelist
            ' Check the boxes!
            selectedString = m_node.Attributes.GetNamedItem("name").Value
            found = False
            For loopvar2 = 1 To grdGems.Rows - 1
                If grdGems.Cell(loopvar2, 2).Text = selectedString Then
                    found = True
                    grdGems.Cell(loopvar2, 1).Text = "1"
                End If
            Next
            If found = False Then
                num_unfound_gems += 1
                ReDim Preserve unfound_gems(0 To num_unfound_gems - 1)
                unfound_gems(num_unfound_gems - 1) = selectedString
            End If
        Next

        ' Enchants.  these of course can't be 'not found'
        m_nodelist = m_xmld.SelectNodes("/config/enchants")
        m_node = m_nodelist(0)
        chkEBoots_Icewalker.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(0).InnerText)
        chkEBoots_Assault.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(1).InnerText)
        chkEGloves_Crusher.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(2).InnerText)
        chkEGloves_Strength.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(3).InnerText)
        chkEGloves_Precision.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(4).InnerText)
        chkEBracers_Assault.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(5).InnerText)
        chkEBracers_Exp.Checked = Convert.ToBoolean(m_node.ChildNodes.Item(6).InnerText)

        ' Misc - these of course also cannot be 'not found'
        m_nodelist = m_xmld.SelectNodes("/config/misc")
        m_node = m_nodelist(0)
        cboRace.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(0).InnerText)
        cboForce_T7.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(1).InnerText)
        cboForce_T8.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(2).InnerText)
        cboForce_T9.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(3).InnerText)
        ' Check item 4 name.  If it's T10 then we're the new version, else old version.
        If m_node.ChildNodes.Item(4).Name = "force_t10" Then
            cboForce_T10.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(4).InnerText)
            cboProf_1.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(5).InnerText)
            cboProf_2.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(6).InnerText)
            cboDWor2H.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(7).InnerText)
            cboSpellTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(8).InnerText)
            cboExpTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(9).InnerText)
            cboArPTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(10).InnerText)
            cboNoCS.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(11).InnerText)
            cboDAura_M.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(12).InnerText)
            cboDAura_S.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(13).InnerText)
            cboForceHitCap.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(14).InnerText)
            cboForceExpertiseCap.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(15).InnerText)
            Try
                cboPrimaryTree.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(16).InnerText)
            Catch ex As Exception
                ' If there was an error, it's an older file and we can set primary tree to "None"
                cboPrimaryTree.SelectedIndex = 0
            End Try
        Else
            cboForce_T10.SelectedIndex = 0
            cboProf_1.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(4).InnerText)
            cboProf_2.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(5).InnerText)
            cboDWor2H.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(6).InnerText)
            cboSpellTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(7).InnerText)
            cboExpTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(8).InnerText)
            cboArPTalents.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(9).InnerText)
            cboNoCS.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(10).InnerText)
            cboDAura_M.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(11).InnerText)
            cboDAura_S.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(12).InnerText)
            cboForceHitCap.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(13).InnerText)
            cboForceExpertiseCap.SelectedIndex = Double.Parse(m_node.ChildNodes.Item(14).InnerText)
        End If


        ' Everything is set, now we have to alert figure out if we
        ' are duplicating a weight set and report to the user
        ' what items / gems were not available.

        ' Weights
        Dim foundMatchingWeights As Boolean = False

        For loopvar = 0 To UBound(weightsNames)
            If Double.Parse(txtStr.Text) = weightsArray(loopvar, 0) And _
                Double.Parse(txtAP.Text) = weightsArray(loopvar, 1) And _
                Double.Parse(txtCrit.Text) = weightsArray(loopvar, 2) And _
                Double.Parse(txtHaste.Text) = weightsArray(loopvar, 3) And _
                Double.Parse(txtArP.Text) = weightsArray(loopvar, 4) And _
                Double.Parse(txtAgi.Text) = weightsArray(loopvar, 5) And _
                Double.Parse(txtArmor.Text) = weightsArray(loopvar, 6) And _
                Double.Parse(txtMeleeHit.Text) = weightsArray(loopvar, 7) And _
                Double.Parse(txtSpellHit.Text) = weightsArray(loopvar, 8) And _
                Double.Parse(txtExtraHit.Text) = weightsArray(loopvar, 9) And _
                Double.Parse(txtExp.Text) = weightsArray(loopvar, 10) And _
                Double.Parse(txtMHDPS.Text) = weightsArray(loopvar, 11) And _
                Double.Parse(txtOHDPS.Text) = weightsArray(loopvar, 12) And _
                Double.Parse(txtMHSpeed.Text) = weightsArray(loopvar, 13) And _
                Double.Parse(txtOHSpeed.Text) = weightsArray(loopvar, 14) And _
                Double.Parse(txtT7_2.Text) = weightsArray(loopvar, 15) And _
                Double.Parse(txtT7_4.Text) = weightsArray(loopvar, 16) And _
                Double.Parse(txtT8_2.Text) = weightsArray(loopvar, 17) And _
                Double.Parse(txtT8_4.Text) = weightsArray(loopvar, 18) And _
                Double.Parse(txtT9_2.Text) = weightsArray(loopvar, 19) And _
                Double.Parse(txtT9_4.Text) = weightsArray(loopvar, 20) And _
                Double.Parse(txtT10_2.Text) = weightsArray(loopvar, 21) And _
                Double.Parse(txtT10_4.Text) = weightsArray(loopvar, 22) And _
                foundMatchingWeights = False Then

                cboWeights.SelectedIndex = loopvar + 1
                foundMatchingWeights = True

            End If
        Next
        ' If no matching weights were found, then this is a custom set.  Set it as such.
        If foundMatchingWeights = False Then
            cboWeights.SelectedIndex = 0
        End If

        ' Items / Gems
        Dim missingString As String = ""
        If num_unfound_items <> 0 Then
            For loopvar = 0 To num_unfound_items - 1
                missingString &= """" & unfound_items(loopvar) & """"
                If loopvar <> num_unfound_items - 1 And num_unfound_items > 2 Then
                    missingString &= ","
                End If
                If loopvar = num_unfound_items - 2 And num_unfound_items > 1 Then
                    missingString &= " and"
                End If
                missingString &= " "
            Next
            If num_unfound_items > 1 Then
                missingString &= "are "
            Else
                missingString &= "is "
            End If
            MessageBox.Show("Due to changes in the Master Item List, " & missingString & "no longer available.  Selection(s) have been lost.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
        End If

        missingString = ""
        If num_unfound_gems <> 0 Then
            For loopvar = 0 To num_unfound_gems - 1
                missingString &= """" & unfound_gems(loopvar) & """"
                If loopvar <> num_unfound_gems - 1 And num_unfound_gems > 2 Then
                    missingString &= ","
                End If
                If loopvar = num_unfound_gems - 2 And num_unfound_gems > 1 Then
                    missingString &= " and"
                End If
                missingString &= " "
            Next
            If num_unfound_gems > 1 Then
                missingString &= "are "
            Else
                missingString &= "is "
            End If
            MessageBox.Show("Due to changes in the Master Gem List, " & missingString & "no longer available.  Selection(s) have been lost.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
        End If

        ' Last thing is set saved to true (after changing all
        ' the combo boxes / values to match the opened file.
        ' if we didn't find some stuff, saved is false
        If num_unfound_gems = 0 And num_unfound_items = 0 Then
            setSaved(True)
        Else
            setSaved(False)
        End If
    End Sub

    Private Sub mnuOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuOpen.Click
        Dim msgresult As DialogResult

        ' If current is unsaved, prompt for save.  Save / Don't save, and then open a file.
        If saved = False Then
            If fileName = "" Then
                msgresult = MessageBox.Show("This document is unsaved.  Save before continuing?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            Else
                msgresult = MessageBox.Show("""" & fileName & """ is unsaved.  Save before continuing?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            End If
            ' If cancel, exit.  If yes, save and move on.
            ' if no, then just move on.
            If msgresult = Windows.Forms.DialogResult.Cancel Then Exit Sub
            If msgresult = Windows.Forms.DialogResult.Yes Then
                Dim tempe As System.EventArgs
                tempe = Nothing
                mnuSave_Click(Me, tempe)
            End If
        End If

        ' Set up options for the open dialog, then show it.
        ' if the user cancels, do nothing else
        ' if the user selects a valid file, then
        ' open it.
        If opnMain.ShowDialog = Windows.Forms.DialogResult.OK Then
            setupNewFile()
            fileName = opnMain.SafeFileName
            filePath = opnMain.FileName
            openFile(filePath)
        End If


    End Sub

    Private Sub mnuSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuSave.Click
        ' Simple save the document, unless we have no filename, then call saveas.
        If fileName = "" Then
            SaveAs()
        Else
            ' just save it
            saveFile(filePath)
        End If
    End Sub

    Private Sub mnuSaveAs_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuSaveAs.Click
        ' Call a different function since we want to be able to call from save as well.
        SaveAs()
    End Sub

    Private Sub SaveAs()
        ' Show the save dialog box, get a filename,
        ' and then set our filepath etc.
        If sveMain.ShowDialog = Windows.Forms.DialogResult.OK Then
            fileName = sveMain.FileName
            fileName = System.IO.Path.GetFileName(fileName)
            filePath = sveMain.FileName
            saveFile(filePath)
        End If
    End Sub

    Private Sub Enchant_checkChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkEBoots_Icewalker.CheckedChanged, chkEBoots_Assault.CheckedChanged, chkEGloves_Crusher.CheckedChanged, chkEGloves_Precision.CheckedChanged, chkEGloves_Strength.CheckedChanged, chkEBracers_Assault.CheckedChanged, chkEBracers_Exp.CheckedChanged
        ' The check was changed, so saved is now false
        setSaved(False)
    End Sub


    Private Sub grid_CheckChange(ByVal Sender As Object, ByVal e As FlexCell.Grid.CellChangeEventArgs) Handles grdGems.CellChange, grdHead.CellChange, grdShoulder.CellChange, grdChest.CellChange, grdHand.CellChange, grdLeg.CellChange, grdNeck.CellChange, grdBack.CellChange, grdWrist.CellChange, grdWaist.CellChange, grdFoot.CellChange, grdFinger.CellChange, grdTrinket.CellChange, grd1HWeapon.CellChange, grd2HWeapon.CellChange
        ' If it was the check column in any of the grids, set it to unsaved.
        If e.Col = 1 And e.Row <> 0 Then
            setSaved(False)
        End If
    End Sub

    Private Sub miscCombo_Change(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboNoCS.SelectedIndexChanged, cboSpellTalents.SelectedIndexChanged, cboExpTalents.SelectedIndexChanged, cboArPTalents.SelectedIndexChanged, cboDAura_M.SelectedIndexChanged, cboDAura_S.SelectedIndexChanged, cboPrimaryTree.SelectedIndexChanged
        ' no longer saved.
        setSaved(False)
    End Sub

    Private Sub mnuExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuExit.Click
        ' Unload
        Me.Close()
    End Sub

    Private Sub mnuEditConstants_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuEditConstants.Click
        ' Open the constants editing form.
        ' We don't need any events here since
        ' the main form will open and read from
        ' the file on calculate.

        Dim frm As New frmEditConstants
        frm.Load_Constants()
        frm.ShowDialog()
        frm = Nothing

    End Sub

    Private Sub Calculate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CalculateToolStripMenuItem.Click
        ' User wants to calculate.  We need to do some validity checking before passing this off to our calculation class.

        Try
            ' Try to leave the text boxes.  If we can't, then exit since there is something invalid.
            cboWeights.Focus()
            If cboWeights.Focused = False Then
                Exit Sub
            End If

            ' We need to make sure that at least one weight is non-zero.
            Dim ctrl As Control
            Dim foundVal As Boolean
            foundVal = False
            For Each ctrl In grpWeights.Controls
                If TypeOf ctrl Is TextBox Then
                    If Double.Parse(ctrl.Text) <> 0 Then
                        foundVal = True
                    End If
                End If
            Next

            If foundVal = False Then
                MessageBox.Show("At least one weight must be non-zero.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                txtStr.Focus()
                Exit Sub
            End If

            ' Need to have selected a primary tree
            If cboPrimaryTree.SelectedIndex = 0 Then
                MessageBox.Show("You must select a primary tree for these weights.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                cboPrimaryTree.Focus()
                Exit Sub
            End If

            ' Need to have at least one enchant selected for each slot.
            ' If the person is an engineer then they already have an enchant
            ' for the gloves and boots, so those can be all unchecked.
            If chkEBracers_Assault.Checked = False And chkEBracers_Exp.Checked = False And cboProf_1.Text <> "Leatherworking" And cboProf_2.Text <> "Leatherworking" Then
                MessageBox.Show("Non-Leatherworkers must select at least one boot enchant.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                chkEBracers_Assault.Focus()
                Exit Sub
            End If

            If chkEBoots_Icewalker.Checked = False And chkEBoots_Assault.Checked = False And cboProf_1.Text <> "Engineering" And cboProf_2.Text <> "Engineering" Then
                MessageBox.Show("Non-Engineers must select at least one boot enchant.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                chkEBoots_Icewalker.Focus()
                Exit Sub
            End If

            If chkEGloves_Crusher.Checked = False And chkEGloves_Precision.Checked = False And chkEGloves_Strength.Checked = False And cboProf_1.Text <> "Engineering" And cboProf_2.Text <> "Engineering" Then
                MessageBox.Show("Non-Engineers must select at least one glove enchant.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                chkEGloves_Crusher.Focus()
                Exit Sub
            End If

            ' Make sure there are valid gems selected.  If a prismatic gem exists, then we are valid.
            ' If a non-unique blue / purple / greem gem exists, we are valid.
            ' If we have some combination of a red / blue / yellow, then we are valid
            ' If we have no non-unique gems, we are invalid.

            Dim loopvar As Integer
            Dim foundBlue As Boolean = False
            Dim foundMultiBlue As Boolean = False
            Dim foundRed As Boolean = False
            Dim foundYellow As Boolean = False
            Dim foundNonUnique As Boolean = False

            For loopvar = 1 To grdGems.Rows - 1
                If grdGems.Cell(loopvar, 1).Text = "1" And grdGems.Cell(loopvar, 3).Text = "None" Then
                    MessageBox.Show("You have selected a gem with no color.  Please edit the gem or deselect it to proceed.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    grdGems.Focus()
                    Exit Sub
                End If
            Next

            For loopvar = 1 To grdGems.Rows - 1
                If grdGems.Cell(loopvar, 1).Text = "1" Then 'If selected
                    Select Case grdGems.Cell(loopvar, 3).Text
                        Case "Red"
                            foundRed = True
                        Case "Yellow"
                            foundYellow = True
                        Case "Orange"
                            foundYellow = True : foundRed = True
                        Case "Blue"
                            If foundBlue = True Or grdGems.Cell(loopvar, grdGems.Cols - 1).Text = "No" Then
                                foundMultiBlue = True
                            End If
                            foundBlue = True
                        Case "Purple"
                            If foundBlue = True Or grdGems.Cell(loopvar, grdGems.Cols - 1).Text = "No" Then
                                foundMultiBlue = True
                            End If
                            foundBlue = True
                            foundRed = True
                        Case "Green"
                            If foundBlue = True Or grdGems.Cell(loopvar, grdGems.Cols - 1).Text = "No" Then
                                foundMultiBlue = True
                            End If
                            foundBlue = True
                            foundYellow = True
                        Case "Prismatic"
                            foundRed = True : foundBlue = True : foundYellow = True
                    End Select
                    If grdGems.Cell(loopvar, grdGems.Cols - 1).Text = "No" Then
                        foundNonUnique = True
                    End If
                End If
            Next

            If foundMultiBlue = False Then
                If foundBlue = False Or foundRed = False Or foundYellow = False Then
                    MessageBox.Show("You have selected gems that cannot meet meta gem requirements. Please re-select gems.", "DK Optimize.", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    grdGems.Focus()
                    Exit Sub
                End If
            End If

            If foundNonUnique = False Then
                MessageBox.Show("Please select at least one non-unique gem.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                grdGems.Focus()
                Exit Sub
            End If

            ' So gems should be valid.  Item wise we have to make sure
            ' that we have one item from every non-weapon slot and
            ' either one two hand weapon or a valid combo of one handed weapons.

            Dim grdArray(0 To 13) As FlexCell.Grid

            grdArray(0) = grdHead
            grdArray(1) = grdShoulder
            grdArray(2) = grdChest
            grdArray(3) = grdHand
            grdArray(4) = grdLeg
            grdArray(5) = grdNeck
            grdArray(6) = grdBack
            grdArray(7) = grdWrist
            grdArray(8) = grdWaist
            grdArray(9) = grdFoot
            grdArray(10) = grdFinger
            grdArray(11) = grdTrinket
            grdArray(12) = grd2HWeapon
            grdArray(13) = grd1HWeapon

            Dim loopvar2 As Integer
            Dim foundForSlot As Boolean

            For loopvar = 0 To 9
                foundForSlot = False
                For loopvar2 = 1 To grdArray(loopvar).Rows - 1
                    If grdArray(loopvar).Cell(loopvar2, 1).Text = "1" Then 'If checked
                        foundForSlot = True
                    End If
                Next
                If foundForSlot = False Then
                    MessageBox.Show("You must select at least one item for each slot.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    Exit Sub
                End If
            Next

            Dim nonUniqueRingFound As Boolean = False
            Dim numRingsfound As Integer = 0

            For loopvar = 1 To grdArray(10).Rows - 1 ' Rings
                If grdArray(10).Cell(loopvar, 1).Text = "1" Then
                    numRingsfound += 1
                    If grdArray(10).Cell(loopvar, 3).Text = "No" Then
                        nonUniqueRingFound = True
                    End If
                End If
            Next

            If numRingsfound < 2 And nonUniqueRingFound = False Then
                MessageBox.Show("You must select at least two rings, or one non-unique ring.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                Exit Sub
            End If

            Dim numTrinketsFound As Integer = 0
            For loopvar = 1 To grdArray(11).Rows - 1 'Trinkets
                If grdArray(11).Cell(loopvar, 1).Text = "1" Then
                    numTrinketsFound += 1
                End If
            Next

            If numTrinketsFound < 2 Then
                MessageBox.Show("You must select at least two trinkets.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                Exit Sub
            End If

            If cboDWor2H.SelectedIndex = 0 Then
                ' 2h
                Dim weaponFound As Boolean = False
                For loopvar = 1 To grdArray(12).Rows - 1 'Two Handed Weapons
                    If grdArray(12).Cell(loopvar, 1).Text = "1" Then
                        weaponFound = True
                    End If
                Next
                If weaponFound = False Then
                    MessageBox.Show("You must select at least one two handed weapon.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    Exit Sub
                End If
            Else
                ' dw
                Dim dwWeaponFound As Boolean = False
                For loopvar = 1 To grdArray(13).Rows - 1 'One Handed Weapons
                    If grdArray(13).Cell(loopvar, 1).Text = "1" Then
                        If grdArray(13).Cell(loopvar, 5).Text = "One Hand" And grdArray(13).Cell(loopvar, 4).Text = "No" Then
                            dwWeaponFound = True
                        End If
                        For loopvar2 = 1 To grdArray(13).Rows - 1
                            If grdArray(13).Cell(loopvar2, 1).Text = "1" And loopvar <> loopvar2 Then
                                Select Case grdArray(13).Cell(loopvar, 5).Text
                                    Case "Main Hand"
                                        If grdArray(13).Cell(loopvar2, 5).Text = "One Hand" Or grdArray(13).Cell(loopvar2, 5).Text = "Off Hand" Then
                                            dwWeaponFound = True
                                        End If
                                    Case "Off Hand"
                                        If grdArray(13).Cell(loopvar2, 5).Text = "One Hand" Or grdArray(13).Cell(loopvar2, 5).Text = "Main Hand" Then
                                            dwWeaponFound = True
                                        End If
                                    Case "One Hand"
                                        dwWeaponFound = True
                                End Select
                            End If
                        Next
                    End If
                Next
                If dwWeaponFound = False Then
                    MessageBox.Show("You must select a valid combination of one-handed weapons.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    Exit Sub
                End If
            End If

            ' Item set bonuses.  Make sure that the selected set bonuses can be met.
            Dim numSlotsFoundT7 As Integer = 0, numSlotsFoundT8 As Integer = 0, numSlotsFoundT9 As Integer = 0, numSlotsFoundT10 As Integer = 0
            Dim curFoundT7 As Boolean, curFoundT8 As Boolean, curFoundT9 As Boolean, curFoundT10 As Boolean

            curFoundT7 = False : curFoundT8 = False : curFoundT9 = False : curFoundT10 = False
            For loopvar = 0 To UBound(items_head)
                For loopvar2 = 0 To grdHead.Rows - 1
                    If grdHead.Cell(loopvar2, 2).Text = items_head(loopvar).name And grdHead.Cell(loopvar2, 1).Text = "1" Then
                        If InStr(items_head(loopvar).name, "Scourgeborne") <> 0 Then curFoundT7 = True
                        If InStr(items_head(loopvar).name, "Darkruned") <> 0 Then curFoundT8 = True
                        If InStr(items_head(loopvar).name, "Koltira's") <> 0 Then curFoundT9 = True
                        If InStr(items_head(loopvar).name, "Scourgelord ") <> 0 Then curFoundT10 = True
                    End If
                Next
            Next
            If curFoundT7 = True Then numSlotsFoundT7 += 1
            If curFoundT8 = True Then numSlotsFoundT8 += 1
            If curFoundT9 = True Then numSlotsFoundT9 += 1
            If curFoundT10 = True Then numSlotsFoundT10 += 1
            curFoundT7 = False : curFoundT8 = False : curFoundT9 = False : curFoundT10 = False
            For loopvar = 0 To UBound(items_shoulder)
                For loopvar2 = 0 To grdShoulder.Rows - 1
                    If grdShoulder.Cell(loopvar2, 2).Text = items_shoulder(loopvar).name And grdShoulder.Cell(loopvar2, 1).Text = "1" Then
                        If InStr(items_shoulder(loopvar).name, "Scourgeborne") <> 0 Then curFoundT7 = True
                        If InStr(items_shoulder(loopvar).name, "Darkruned") <> 0 Then curFoundT8 = True
                        If InStr(items_shoulder(loopvar).name, "Koltira's") <> 0 Then curFoundT9 = True
                        If InStr(items_shoulder(loopvar).name, "Scourgelord ") <> 0 Then curFoundT10 = True
                    End If
                Next
            Next
            If curFoundT7 = True Then numSlotsFoundT7 += 1
            If curFoundT8 = True Then numSlotsFoundT8 += 1
            If curFoundT9 = True Then numSlotsFoundT9 += 1
            If curFoundT10 = True Then numSlotsFoundT10 += 1
            curFoundT7 = False : curFoundT8 = False : curFoundT9 = False : curFoundT10 = False
            For loopvar = 0 To UBound(items_chest)
                For loopvar2 = 0 To grdChest.Rows - 1
                    If grdChest.Cell(loopvar2, 2).Text = items_chest(loopvar).name And grdChest.Cell(loopvar2, 1).Text = "1" Then
                        If InStr(items_chest(loopvar).name, "Scourgeborne") <> 0 Then curFoundT7 = True
                        If InStr(items_chest(loopvar).name, "Darkruned") <> 0 Then curFoundT8 = True
                        If InStr(items_chest(loopvar).name, "Koltira's") <> 0 Then curFoundT9 = True
                        If InStr(items_chest(loopvar).name, "Scourgelord ") <> 0 Then curFoundT10 = True
                    End If
                Next
            Next
            If curFoundT7 = True Then numSlotsFoundT7 += 1
            If curFoundT8 = True Then numSlotsFoundT8 += 1
            If curFoundT9 = True Then numSlotsFoundT9 += 1
            If curFoundT10 = True Then numSlotsFoundT10 += 1
            curFoundT7 = False : curFoundT8 = False : curFoundT9 = False : curFoundT10 = False
            For loopvar = 0 To UBound(items_hand)
                For loopvar2 = 0 To grdHand.Rows - 1
                    If grdHand.Cell(loopvar2, 2).Text = items_hand(loopvar).name And grdHand.Cell(loopvar2, 1).Text = "1" Then
                        If InStr(items_hand(loopvar).name, "Scourgeborne") <> 0 Then curFoundT7 = True
                        If InStr(items_hand(loopvar).name, "Darkruned") <> 0 Then curFoundT8 = True
                        If InStr(items_hand(loopvar).name, "Koltira's") <> 0 Then curFoundT9 = True
                        If InStr(items_hand(loopvar).name, "Scourgelord ") <> 0 Then curFoundT10 = True
                    End If
                Next
            Next
            If curFoundT7 = True Then numSlotsFoundT7 += 1
            If curFoundT8 = True Then numSlotsFoundT8 += 1
            If curFoundT9 = True Then numSlotsFoundT9 += 1
            If curFoundT10 = True Then numSlotsFoundT10 += 1
            curFoundT7 = False : curFoundT8 = False : curFoundT9 = False : curFoundT10 = False
            For loopvar = 0 To UBound(items_leg)
                For loopvar2 = 0 To grdLeg.Rows - 1
                    If grdLeg.Cell(loopvar2, 2).Text = items_leg(loopvar).name And grdLeg.Cell(loopvar2, 1).Text = "1" Then
                        If InStr(items_leg(loopvar).name, "Scourgeborne") <> 0 Then curFoundT7 = True
                        If InStr(items_leg(loopvar).name, "Darkruned") <> 0 Then curFoundT8 = True
                        If InStr(items_leg(loopvar).name, "Koltira's") <> 0 Then curFoundT9 = True
                        If InStr(items_leg(loopvar).name, "Scourgelord ") <> 0 Then curFoundT10 = True
                    End If
                Next
            Next
            If curFoundT7 = True Then numSlotsFoundT7 += 1
            If curFoundT8 = True Then numSlotsFoundT8 += 1
            If curFoundT9 = True Then numSlotsFoundT9 += 1
            If curFoundT10 = True Then numSlotsFoundT10 += 1
            If numSlotsFoundT7 < Double.Parse(cboForce_T7.Text) Or numSlotsFoundT8 < Double.Parse(cboForce_T8.Text) Or numSlotsFoundT9 < Double.Parse(cboForce_T9.Text) Or numSlotsFoundT10 < Double.Parse(cboForce_T10.Text) Then
                MessageBox.Show("You have forced a Tier Set bonus that cannot be met with the selected items.  Please re-select items or change the forced bonuses.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                Exit Sub
            End If

            ' Now to verify slot colors for every item selected.
            ' Rules: sockets can be none, but they must start at the first socket
            ' i.e. socket 1 can't be none if socket 2 isn't none.
            ' if you have one non-none socket, the bonus stat can't be none.
            ' if you have no sockets, bonus and bonusstat must be zero / none.
            Dim socketstart(0 To 13) As Integer

            socketstart(0) = 12
            socketstart(1) = 12
            socketstart(2) = 12
            socketstart(3) = 12
            socketstart(4) = 12
            socketstart(5) = 12
            socketstart(6) = 12
            socketstart(7) = 12
            socketstart(8) = 12
            socketstart(9) = 12
            socketstart(10) = 13
            socketstart(11) = 15
            socketstart(12) = 15
            socketstart(13) = 17


            For loopvar = 0 To 13
                ' We don't need to check the non-relevant weapons
                If (cboDWor2H.SelectedIndex = 0 And loopvar <> 13) Or (cboDWor2H.SelectedIndex = 1 And loopvar <> 12) Then
                    For loopvar2 = 1 To grdArray(loopvar).Rows - 1
                        If grdArray(loopvar).Cell(loopvar2, 1).Text = "1" Then
                            If grdArray(loopvar).Cell(loopvar2, socketstart(loopvar) + 2).Text <> "None" And grdArray(loopvar).Cell(loopvar2, socketstart(loopvar) + 1).Text = "None" Then
                                MessageBox.Show("You have selected an item with invalid sockets.  Please reselect items or change the master item list.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                                Exit Sub
                            End If
                            If grdArray(loopvar).Cell(loopvar2, socketstart(loopvar) + 1).Text <> "None" And grdArray(loopvar).Cell(loopvar2, socketstart(loopvar)).Text = "None" Then
                                MessageBox.Show("You have selected an item with invalid sockets.  Please reselect items or change the master item list.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                                Exit Sub
                            End If
                            If grdArray(loopvar).Cell(loopvar2, socketstart(loopvar)).Text <> "None" And grdArray(loopvar).Cell(loopvar2, socketstart(loopvar) + 4).Text = "None" Then
                                MessageBox.Show("All items with sockets must have a socket bonus. Please reselect items or change the master item list.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                                Exit Sub
                            End If
                            If grdArray(loopvar).Cell(loopvar2, socketstart(loopvar)).Text = "None" And grdArray(loopvar).Cell(loopvar2, socketstart(loopvar) + 4).Text <> "None" Then
                                MessageBox.Show("Items with no sockets cannot have a socket bonus. Please reselect items or change the master item list.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                                Exit Sub
                            End If
                        End If
                    Next
                End If
            Next

            ' Everything is valid, so set up our Calculation.
            ' Call our CalcManager class and then set it up.
            myCalc = New CalcManager

            myCalc.setDWor2H(cboDWor2H.Text)
            myCalc.setPlayerRace(cboRace.Text)
            myCalc.setPlayerProfs(cboProf_1.Text, cboProf_2.Text)
            myCalc.setForceTier(Double.Parse(cboForce_T7.Text), Double.Parse(cboForce_T8.Text), Double.Parse(cboForce_T9.Text), Double.Parse(cboForce_T10.Text))

            For loopvar = 1 To grdGems.Rows - 1
                If grdGems.Cell(loopvar, 1).Text = "1" Then
                    For loopvar2 = 0 To UBound(gems)
                        If gems(loopvar2).name = grdGems.Cell(loopvar, 2).Text Then
                            myCalc.addGem(gems(loopvar2))
                        End If
                    Next
                End If
            Next

            ' Adding items a pain since I'm dumb and didn't make a 2D array.
            With grdHead
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_head)
                            If items_head(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_head(loopvar2), "head")
                            End If
                        Next
                    End If
                Next
            End With

            With grdShoulder
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_shoulder)
                            If items_shoulder(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_shoulder(loopvar2), "shoulder")
                            End If
                        Next
                    End If
                Next
            End With

            With grdChest
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_chest)
                            If items_chest(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_chest(loopvar2), "chest")
                            End If
                        Next
                    End If
                Next
            End With

            With grdHand
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_hand)
                            If items_hand(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_hand(loopvar2), "hand")
                            End If
                        Next
                    End If
                Next
            End With

            With grdLeg
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_leg)
                            If items_leg(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_leg(loopvar2), "leg")
                            End If
                        Next
                    End If
                Next
            End With

            With grdNeck
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_neck)
                            If items_neck(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_neck(loopvar2), "neck")
                            End If
                        Next
                    End If
                Next
            End With

            With grdBack
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_back)
                            If items_back(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_back(loopvar2), "back")
                            End If
                        Next
                    End If
                Next
            End With

            With grdWrist
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_wrist)
                            If items_wrist(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_wrist(loopvar2), "wrist")
                            End If
                        Next
                    End If
                Next
            End With

            With grdWaist
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_waist)
                            If items_waist(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_waist(loopvar2), "waist")
                            End If
                        Next
                    End If
                Next
            End With

            With grdFoot
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_foot)
                            If items_foot(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_foot(loopvar2), "foot")
                            End If
                        Next
                    End If
                Next
            End With

            With grdFinger
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_finger)
                            If items_finger(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_finger(loopvar2), "finger")
                            End If
                        Next
                    End If
                Next
            End With

            With grdTrinket
                For loopvar = 1 To .Rows - 1
                    If .Cell(loopvar, 1).Text = "1" Then
                        For loopvar2 = 0 To UBound(items_trinket)
                            If items_trinket(loopvar2).name = .Cell(loopvar, 2).Text Then
                                myCalc.addItem(items_trinket(loopvar2), "trinket")
                            End If
                        Next
                    End If
                Next
            End With

            If cboDWor2H.Text = "Dual Wield" Then
                With grd1HWeapon
                    For loopvar = 1 To .Rows - 1
                        If .Cell(loopvar, 1).Text = "1" Then
                            For loopvar2 = 0 To UBound(items_onehand)
                                If items_onehand(loopvar2).name = .Cell(loopvar, 2).Text Then
                                    myCalc.addItem(items_onehand(loopvar2), "onehand")
                                End If
                            Next
                        End If
                    Next
                End With
            Else
                With grd2HWeapon
                    For loopvar = 1 To .Rows - 1
                        If .Cell(loopvar, 1).Text = "1" Then
                            For loopvar2 = 0 To UBound(items_twohand)
                                If items_twohand(loopvar2).name = .Cell(loopvar, 2).Text Then
                                    myCalc.addItem(items_twohand(loopvar2), "twohand")
                                End If
                            Next
                        End If
                    Next
                End With
            End If

            ' Weights
            myCalc.setWeights(Double.Parse(txtStr.Text), Double.Parse(txtAP.Text), Double.Parse(txtCrit.Text), Double.Parse(txtHaste.Text), Double.Parse(txtArP.Text), Double.Parse(txtAgi.Text), Double.Parse(txtArmor.Text), Double.Parse(txtMeleeHit.Text), Double.Parse(txtSpellHit.Text), Double.Parse(txtExtraHit.Text), Double.Parse(txtExp.Text), _
                              Double.Parse(txtMHDPS.Text), Double.Parse(txtOHDPS.Text), Double.Parse(txtMHSpeed.Text), Double.Parse(txtOHSpeed.Text), Double.Parse(txtT7_2.Text), Double.Parse(txtT7_4.Text), Double.Parse(txtT8_2.Text), Double.Parse(txtT8_4.Text), Double.Parse(txtT9_2.Text), Double.Parse(txtT9_4.Text), Double.Parse(txtT10_2.Text), Double.Parse(txtT10_4.Text))

            ' Enchants
            If chkEBoots_Assault.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.foot_GreaterAssault)
            If chkEBoots_Icewalker.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.foot_Icewalker)
            If chkEGloves_Crusher.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.hand_Crusher)
            If chkEGloves_Precision.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.hand_Precision)
            If chkEGloves_Strength.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.hand_MajorStrength)
            If chkEBracers_Assault.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.wrist_GreaterAssault)
            If chkEBracers_Exp.Checked = True Then myCalc.addEnchant(CalcManager.Enchants.wrist_Expertise)

            ' We've passed calc all the data it needs to store, so call it with the the rest of what it needs
            ' to calculate caps etc and let it start calculating.
            Dim mAura As Boolean, sAura As Boolean
            If cboDAura_M.Text = "No" Or cboDAura_M.Visible = False Then
                mAura = False
            Else
                mAura = True
            End If
            If cboDAura_S.Text = "No" Or cboDAura_S.Visible = False Then
                sAura = False
            Else
                sAura = True
            End If

            calcdone = False

            ' Get the stuff for the hit forcing and exp forcing
            Dim forcehittemp As GemValidityMatrix.forceHitCap
            Select Case cboForceHitCap.Text
                Case "None"
                    forcehittemp = GemValidityMatrix.forceHitCap.none
                Case "Melee"
                    forcehittemp = GemValidityMatrix.forceHitCap.melee
                Case "Spell"
                    forcehittemp = GemValidityMatrix.forceHitCap.spell
            End Select
            Dim forceexptemp As Boolean
            If cboForceExpertiseCap.Text = "No" Then
                forceexptemp = False
            Else
                forceexptemp = True
            End If

            Dim tempint As Integer

            If cboDWor2H.Text = "Dual Wield" Then
                tempint = cboNoCS.SelectedIndex
            Else
                tempint = 0
            End If

            myCalc.finalVars(cboSpellTalents.SelectedIndex, cboExpTalents.SelectedIndex, cboArPTalents.SelectedIndex * 2, tempint, mAura, sAura, forcehittemp, forceexptemp, cboPrimaryTree.Text)
            myCalc.shouldCancel = False

            noCandidatesFound = False
            noGemSetsFound = False

            ' Ready to calculate, start a new thread and hide myself while showing the progress form.
            Dim calcThread As System.Threading.Thread
            calcThread = New System.Threading.Thread(AddressOf myCalc.doCalc)
            calcThread.Start()


            progressForm = New frmProgress

            Me.Hide()
            progressForm.progStart()
            ' The remainder of the updates to the progress form will be done via event handling to 
            ' keep it in communication with mycalc.
            ' lots of scope hopping, but it shouldn't be too bad.  Probably going to push a timer and
            ' just update once per second from mycalc stuff.

            ' Show the main form again.
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try

    End Sub

    Private Sub myCalc_CalculateFinish(ByVal bestSetIN As FullSet) Handles myCalc.CalculateFinish

        ' Calculation has finished, so we need to show the results form and
        ' populate it with the results values.
        ' Note that we will leave the main form shown for this 
        ' and show the results form modally, since that's how we've handled
        ' all the other forms.
        '
        ' The exception was made for calculation since that is pretty time consuming and
        ' there's no reason to leave the main form showing.
        Try
            bestSet = bestSetIN
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try
    End Sub

    Private Sub frmprogress_alldone() Handles progressForm.allDone
        ' Show the results form when the progress form reports that all is completed.
        Try
            Dim frmResult As frmResults
            frmResult = New frmResults
            frmResult.sendSet(bestSet)
            frmResult.ShowDialog()
            previousResultsExist = True
            myCalc = Nothing
            Me.Show()
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try

    End Sub

    Private Sub progressForm_cancelCalc() Handles progressForm.cancelCalc
        ' Cancel the calculation and get everything cleared up.
        Try
            myCalc.shouldCancel = True
            myCalc = Nothing
            Me.Show()
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try
    End Sub

    Private Sub progressForm_errorDone() Handles progressForm.errorDone
        ' If the calculation ended in error, it's basically the same as canceling the calculation.
        progressForm_cancelCalc()
    End Sub

    Private Sub progressForm_timerFire() Handles progressForm.timerFire
        ' Update progressform variables.
        Try
            Dim tempdouble As Double

            ' Error progress tracking.
            progressForm.nogemsfound = noGemSetsFound
            progressForm.nocandidatesfound = noCandidatesFound

            ' Candidatepercent
            If myCalc.candidatesDone = False Then
                tempdouble = 100 * myCalc.candidatesChecked / myCalc.candidatesToCheck
                If tempdouble > 100 Then tempdouble = 100
                progressForm.candidatePercent = tempdouble
                progressForm.candidateDone = False
            Else
                progressForm.candidatePercent = 100
                progressForm.candidateDone = True
                If myCalc.progGemsDone = False Then
                    If myCalc.gemsToCheck <> 0 Then
                        tempdouble = 100 * myCalc.gemsChecked / myCalc.gemsToCheck
                        If tempdouble > 100 Then tempdouble = 100
                        progressForm.gemPercent = tempdouble
                        progressForm.gemDone = False
                    Else
                        progressForm.gemPercent = 0
                        progressForm.gemDone = False
                    End If
                Else
                    progressForm.gemPercent = 100
                    progressForm.gemDone = True
                End If
                End If
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try

    End Sub

    Private Sub mnuViewLastResults_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuViewLastResults.Click
        Try
            ' Redisplay the results if there are any
            If previousResultsExist = True Then
                Dim frmResult As frmResults
                frmResult = New frmResults
                frmResult.sendSet(bestSet)
                Me.Hide()
                frmResult.ShowDialog()
                Me.Show()
            Else
                MessageBox.Show("No results exist yet.  Run a calculation before using this feature.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            End If
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            MessageBox.Show("An unexpected error has occurred. DK Optimize will exit.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            ErrLogWriter.writeLog(ex)
            End
        End Try
    End Sub

    Private Sub myCalc_NoCandidateSets() Handles myCalc.NoCandidateSets
        ' This is called when candidate set finding has finished and no sets are found.
        ' Basically due to hit / exp conditions not being able to be satisfied.
        noCandidatesFound = True
    End Sub

    Private Sub myCalc_NoGemSets() Handles myCalc.NoGemSets
        ' This is called when gemming finishes but no sets are found.
        ' Almost always due to hit / exp cap forcing issues.
        noGemSetsFound = True
    End Sub

    Private Sub AboutDKOptimizeToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutDKOptimizeToolStripMenuItem.Click
        ' Show the help dialog.
        Dim myAbout As frmAbout
        myAbout = New frmAbout

        myAbout.ShowDialog()

    End Sub

    Private Sub EditInternalProcsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles EditInternalProcsToolStripMenuItem.Click
        Dim myInternalProcs As frmEditInternalProcs
        myInternalProcs = New frmEditInternalProcs

        myInternalProcs.Load_InternalProcs()
        myInternalProcs.ShowDialog()
        myInternalProcs = Nothing
    End Sub
End Class